Importing rustc-1.63.0

Test: ./build.py --lto=thin
Bug: 241303140
Change-Id: I967a77fc8365f26b17c8b9b70d5a2d64d948dd86
diff --git a/compiler/rustc/Cargo.toml b/compiler/rustc/Cargo.toml
index b642e89..27ee3dd 100644
--- a/compiler/rustc/Cargo.toml
+++ b/compiler/rustc/Cargo.toml
@@ -9,14 +9,17 @@
 # Make sure rustc_codegen_ssa ends up in the sysroot, because this
 # crate is intended to be used by codegen backends, which may not be in-tree.
 rustc_codegen_ssa = { path = "../rustc_codegen_ssa" }
+# Make sure rustc_smir ends up in the sysroot, because this
+# crate is intended to be used by stable MIR consumers, which are not in-tree
+rustc_smir = { path = "../rustc_smir" }
 
-[dependencies.tikv-jemalloc-sys]
-version = '0.4.0'
+[dependencies.jemalloc-sys]
+version = "0.5.0"
 optional = true
 features = ['unprefixed_malloc_on_supported_platforms']
 
 [features]
-jemalloc = ['tikv-jemalloc-sys']
+jemalloc = ['jemalloc-sys']
 llvm = ['rustc_driver/llvm']
 max_level_info = ['rustc_driver/max_level_info']
 rustc_use_parallel_compiler = ['rustc_driver/rustc_use_parallel_compiler']
diff --git a/compiler/rustc/Windows Manifest.xml b/compiler/rustc/Windows Manifest.xml
new file mode 100644
index 0000000..b37a2fd
--- /dev/null
+++ b/compiler/rustc/Windows Manifest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!--
+This is a Windows application manifest file.
+See: https://docs.microsoft.com/en-us/windows/win32/sbscs/application-manifests
+-->
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
+    <!-- Versions rustc supports as compiler hosts -->
+    <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1"> 
+        <application> 
+            <!-- Windows 7 --><supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
+            <!-- Windows 8 --><supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
+            <!-- Windows 8.1 --><supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
+            <!-- Windows 10 and 11 --><supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
+        </application> 
+    </compatibility>
+    <!-- Use UTF-8 code page -->
+    <asmv3:application>
+        <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2019/WindowsSettings">
+            <activeCodePage>UTF-8</activeCodePage>
+        </asmv3:windowsSettings>
+    </asmv3:application>
+    <!-- Remove (most) legacy path limits -->
+    <asmv3:application>
+        <asmv3:windowsSettings xmlns:ws2="http://schemas.microsoft.com/SMI/2016/WindowsSettings">
+            <ws2:longPathAware>true</ws2:longPathAware>
+        </asmv3:windowsSettings>
+    </asmv3:application>
+</assembly>
diff --git a/compiler/rustc/build.rs b/compiler/rustc/build.rs
new file mode 100644
index 0000000..24c06c0
--- /dev/null
+++ b/compiler/rustc/build.rs
@@ -0,0 +1,24 @@
+use std::env;
+
+fn main() {
+    let target_os = env::var("CARGO_CFG_TARGET_OS");
+    let target_env = env::var("CARGO_CFG_TARGET_ENV");
+    if Ok("windows") == target_os.as_deref() && Ok("msvc") == target_env.as_deref() {
+        set_windows_exe_options();
+    }
+}
+
+// Add a manifest file to rustc.exe.
+fn set_windows_exe_options() {
+    static WINDOWS_MANIFEST_FILE: &str = "Windows Manifest.xml";
+
+    let mut manifest = env::current_dir().unwrap();
+    manifest.push(WINDOWS_MANIFEST_FILE);
+
+    println!("cargo:rerun-if-changed={}", WINDOWS_MANIFEST_FILE);
+    // Embed the Windows application manifest file.
+    println!("cargo:rustc-link-arg-bin=rustc-main=/MANIFEST:EMBED");
+    println!("cargo:rustc-link-arg-bin=rustc-main=/MANIFESTINPUT:{}", manifest.to_str().unwrap());
+    // Turn linker warnings into errors.
+    println!("cargo:rustc-link-arg-bin=rustc-main=/WX");
+}
diff --git a/compiler/rustc/src/main.rs b/compiler/rustc/src/main.rs
index 4edd095..0de1a78 100644
--- a/compiler/rustc/src/main.rs
+++ b/compiler/rustc/src/main.rs
@@ -22,12 +22,10 @@
 // The two crates we link to here, `std` and `rustc_driver`, are both dynamic
 // libraries. So we must reference jemalloc symbols one way or another, because
 // this file is the only object code in the rustc executable.
-#[cfg(feature = "tikv-jemalloc-sys")]
-use tikv_jemalloc_sys as jemalloc_sys;
 
 fn main() {
     // See the comment at the top of this file for an explanation of this.
-    #[cfg(feature = "tikv-jemalloc-sys")]
+    #[cfg(feature = "jemalloc-sys")]
     {
         use std::os::raw::{c_int, c_void};
 
diff --git a/compiler/rustc_apfloat/src/lib.rs b/compiler/rustc_apfloat/src/lib.rs
index 143c6f7..cfc3d5b 100644
--- a/compiler/rustc_apfloat/src/lib.rs
+++ b/compiler/rustc_apfloat/src/lib.rs
@@ -33,7 +33,6 @@
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![no_std]
 #![forbid(unsafe_code)]
-#![feature(nll)]
 
 #[macro_use]
 extern crate alloc;
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 5a4c997..e5b61d7 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -23,15 +23,15 @@
 pub use UnsafeSource::*;
 
 use crate::ptr::P;
-use crate::token::{self, CommentKind, Delimiter, Token, TokenKind};
-use crate::tokenstream::{DelimSpan, LazyTokenStream, TokenStream, TokenTree};
+use crate::token::{self, CommentKind, Delimiter};
+use crate::tokenstream::{DelimSpan, LazyTokenStream, TokenStream};
 
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_data_structures::sync::Lrc;
 use rustc_data_structures::thin_vec::ThinVec;
 use rustc_macros::HashStable_Generic;
-use rustc_serialize::{self, Decoder, Encoder};
+use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
 use rustc_span::source_map::{respan, Spanned};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{Span, DUMMY_SP};
@@ -41,9 +41,6 @@
 use std::fmt;
 use std::mem;
 
-#[cfg(test)]
-mod tests;
-
 /// A "Label" is an identifier of some point in sources,
 /// e.g. in the following code:
 ///
@@ -444,8 +441,7 @@
 pub struct WhereClause {
     /// `true` if we ate a `where` token: this can happen
     /// if we parsed no predicates (e.g. `struct Foo where {}`).
-    /// This allows us to accurately pretty-print
-    /// in `nt_to_tokenstream`
+    /// This allows us to pretty-print accurately.
     pub has_where_token: bool,
     pub predicates: Vec<WherePredicate>,
     pub span: Span,
@@ -1282,6 +1278,22 @@
             },
         )
     }
+
+    // To a first-order approximation, is this a pattern
+    pub fn is_approximately_pattern(&self) -> bool {
+        match &self.peel_parens().kind {
+            ExprKind::Box(_)
+            | ExprKind::Array(_)
+            | ExprKind::Call(_, _)
+            | ExprKind::Tup(_)
+            | ExprKind::Lit(_)
+            | ExprKind::Range(_, _, _)
+            | ExprKind::Underscore
+            | ExprKind::Path(_, _)
+            | ExprKind::Struct(_) => true,
+            _ => false,
+        }
+    }
 }
 
 /// Limit types of a range (inclusive or exclusive)
@@ -1571,20 +1583,7 @@
         match self {
             MacArgs::Empty => TokenStream::default(),
             MacArgs::Delimited(.., tokens) => tokens.clone(),
-            MacArgs::Eq(_, MacArgsEq::Ast(expr)) => {
-                // Currently only literals are allowed here. If more complex expression kinds are
-                // allowed in the future, then `nt_to_tokenstream` should be used to extract the
-                // token stream. This will require some cleverness, perhaps with a function
-                // pointer, because `nt_to_tokenstream` is not directly usable from this crate.
-                // It will also require changing the `parse_expr` call in `parse_mac_args_common`
-                // to `parse_expr_force_collect`.
-                if let ExprKind::Lit(lit) = &expr.kind {
-                    let token = Token::new(TokenKind::Literal(lit.token), lit.span);
-                    TokenTree::Token(token).into()
-                } else {
-                    unreachable!("couldn't extract literal when getting inner tokens: {:?}", expr)
-                }
-            }
+            MacArgs::Eq(_, MacArgsEq::Ast(expr)) => TokenStream::from_ast(expr),
             MacArgs::Eq(_, MacArgsEq::Hir(lit)) => {
                 unreachable!("in literal form when getting inner tokens: {:?}", lit)
             }
@@ -1976,6 +1975,8 @@
     pub ext: Extern,
     pub generic_params: Vec<GenericParam>,
     pub decl: P<FnDecl>,
+    /// Span of the `fn(...) -> ...` part.
+    pub decl_span: Span,
 }
 
 /// The various kinds of type recognized by the compiler.
@@ -2487,13 +2488,11 @@
     }
 }
 
-impl<S: Encoder> rustc_serialize::Encodable<S> for AttrId {
-    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
-        s.emit_unit()
-    }
+impl<S: Encoder> Encodable<S> for AttrId {
+    fn encode(&self, _s: &mut S) {}
 }
 
-impl<D: Decoder> rustc_serialize::Decodable<D> for AttrId {
+impl<D: Decoder> Decodable<D> for AttrId {
     fn decode(_: &mut D) -> AttrId {
         crate::attr::mk_attr_id()
     }
@@ -2564,15 +2563,6 @@
     }
 }
 
-#[derive(Copy, Clone, Encodable, Decodable, Debug, HashStable_Generic)]
-pub enum CrateSugar {
-    /// Source is `pub(crate)`.
-    PubCrate,
-
-    /// Source is (just) `crate`.
-    JustCrate,
-}
-
 #[derive(Clone, Encodable, Decodable, Debug)]
 pub struct Visibility {
     pub kind: VisibilityKind,
@@ -2583,7 +2573,6 @@
 #[derive(Clone, Encodable, Decodable, Debug)]
 pub enum VisibilityKind {
     Public,
-    Crate(CrateSugar),
     Restricted { path: P<Path>, id: NodeId },
     Inherited,
 }
diff --git a/compiler/rustc_ast/src/ast/tests.rs b/compiler/rustc_ast/src/ast/tests.rs
deleted file mode 100644
index 8ba55bf..0000000
--- a/compiler/rustc_ast/src/ast/tests.rs
+++ /dev/null
@@ -1,11 +0,0 @@
-use super::*;
-
-// Are ASTs encodable?
-#[test]
-fn check_asts_encodable() {
-    fn assert_encodable<
-        T: for<'a> rustc_serialize::Encodable<rustc_serialize::json::Encoder<'a>>,
-    >() {
-    }
-    assert_encodable::<Crate>();
-}
diff --git a/compiler/rustc_ast/src/ast_traits.rs b/compiler/rustc_ast/src/ast_traits.rs
index bd401dd..5c30a75 100644
--- a/compiler/rustc_ast/src/ast_traits.rs
+++ b/compiler/rustc_ast/src/ast_traits.rs
@@ -108,7 +108,7 @@
     };
 }
 
-impl_has_span!(AssocItem, Expr, ForeignItem, Item, Stmt);
+impl_has_span!(AssocItem, Block, Expr, ForeignItem, Item, Pat, Path, Stmt, Ty, Visibility);
 
 impl<T: AstDeref<Target: HasSpan>> HasSpan for T {
     fn span(&self) -> Span {
@@ -116,6 +116,12 @@
     }
 }
 
+impl HasSpan for AttrItem {
+    fn span(&self) -> Span {
+        self.span()
+    }
+}
+
 /// A trait for AST nodes having (or not having) collected tokens.
 pub trait HasTokens {
     fn tokens(&self) -> Option<&LazyTokenStream>;
diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs
index 84654a9..988918b 100644
--- a/compiler/rustc_ast/src/attr/mod.rs
+++ b/compiler/rustc_ast/src/attr/mod.rs
@@ -340,7 +340,7 @@
     NestedMetaItem::MetaItem(mk_word_item(ident))
 }
 
-crate fn mk_attr_id() -> AttrId {
+pub(crate) fn mk_attr_id() -> AttrId {
     use std::sync::atomic::AtomicU32;
     use std::sync::atomic::Ordering;
 
@@ -552,7 +552,7 @@
     ) -> Option<MetaItemKind> {
         match tokens.next() {
             Some(TokenTree::Delimited(_, Delimiter::Invisible, inner_tokens)) => {
-                MetaItemKind::name_value_from_tokens(&mut inner_tokens.trees())
+                MetaItemKind::name_value_from_tokens(&mut inner_tokens.into_trees())
             }
             Some(TokenTree::Token(token)) => {
                 Lit::from_token(&token).ok().map(MetaItemKind::NameValue)
diff --git a/compiler/rustc_ast/src/entry.rs b/compiler/rustc_ast/src/entry.rs
index c0a8379..3370146 100644
--- a/compiler/rustc_ast/src/entry.rs
+++ b/compiler/rustc_ast/src/entry.rs
@@ -2,7 +2,7 @@
 pub enum EntryPointType {
     None,
     MainNamed,
-    MainAttr,
+    RustcMainAttr,
     Start,
     OtherMain, // Not an entry point, but some other function named main
 }
diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs
index 1246716..4b94ec0 100644
--- a/compiler/rustc_ast/src/lib.rs
+++ b/compiler/rustc_ast/src/lib.rs
@@ -12,13 +12,11 @@
 #![feature(box_patterns)]
 #![feature(const_default_impls)]
 #![feature(const_trait_impl)]
-#![feature(crate_visibility_modifier)]
 #![feature(if_let_guard)]
 #![feature(label_break_value)]
 #![feature(let_chains)]
 #![feature(min_specialization)]
 #![feature(negative_impls)]
-#![feature(nll)]
 #![feature(slice_internals)]
 #![feature(stmt_expr_attributes)]
 #![recursion_limit = "256"]
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index b425b5e..85bb529 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -460,10 +460,11 @@
             vis.visit_mt(mt);
         }
         TyKind::BareFn(bft) => {
-            let BareFnTy { unsafety, ext: _, generic_params, decl } = bft.deref_mut();
+            let BareFnTy { unsafety, ext: _, generic_params, decl, decl_span } = bft.deref_mut();
             visit_unsafety(unsafety, vis);
             generic_params.flat_map_in_place(|param| vis.flat_map_generic_param(param));
             vis.visit_fn_decl(decl);
+            vis.visit_span(decl_span);
         }
         TyKind::Tup(tys) => visit_vec(tys, |ty| vis.visit_ty(ty)),
         TyKind::Paren(ty) => vis.visit_ty(ty),
@@ -1468,7 +1469,7 @@
 
 pub fn noop_visit_vis<T: MutVisitor>(visibility: &mut Visibility, vis: &mut T) {
     match &mut visibility.kind {
-        VisibilityKind::Public | VisibilityKind::Crate(_) | VisibilityKind::Inherited => {}
+        VisibilityKind::Public | VisibilityKind::Inherited => {}
         VisibilityKind::Restricted { path, id } => {
             vis.visit_path(path);
             vis.visit_id(id);
diff --git a/compiler/rustc_ast/src/ptr.rs b/compiler/rustc_ast/src/ptr.rs
index 89a0857..30481ed 100644
--- a/compiler/rustc_ast/src/ptr.rs
+++ b/compiler/rustc_ast/src/ptr.rs
@@ -10,7 +10,7 @@
 //!
 //! * **Immutability**: `P<T>` disallows mutating its inner `T`, unlike `Box<T>`
 //!   (unless it contains an `Unsafe` interior, but that may be denied later).
-//!   This mainly prevents mistakes, but can also enforces a kind of "purity".
+//!   This mainly prevents mistakes, but also enforces a kind of "purity".
 //!
 //! * **Efficiency**: folding can reuse allocation space for `P<T>` and `Vec<T>`,
 //!   the latter even when the input and output types differ (as it would be the
@@ -121,8 +121,8 @@
 }
 
 impl<S: Encoder, T: Encodable<S>> Encodable<S> for P<T> {
-    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
-        (**self).encode(s)
+    fn encode(&self, s: &mut S) {
+        (**self).encode(s);
     }
 }
 
@@ -191,8 +191,8 @@
 }
 
 impl<S: Encoder, T: Encodable<S>> Encodable<S> for P<[T]> {
-    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
-        Encodable::encode(&**self, s)
+    fn encode(&self, s: &mut S) {
+        Encodable::encode(&**self, s);
     }
 }
 
diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs
index 72dd44a..85d9687 100644
--- a/compiler/rustc_ast/src/token.rs
+++ b/compiler/rustc_ast/src/token.rs
@@ -133,7 +133,7 @@
         }
     }
 
-    crate fn may_have_suffix(self) -> bool {
+    pub(crate) fn may_have_suffix(self) -> bool {
         matches!(self, Integer | Float | Err)
     }
 }
diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs
index a8f29f3..37de90d 100644
--- a/compiler/rustc_ast/src/tokenstream.rs
+++ b/compiler/rustc_ast/src/tokenstream.rs
@@ -13,7 +13,9 @@
 //! and a borrowed `TokenStream` is sufficient to build an owned `TokenStream` without taking
 //! ownership of the original.
 
-use crate::token::{self, Delimiter, Token, TokenKind};
+use crate::ast::StmtKind;
+use crate::ast_traits::{HasAttrs, HasSpan, HasTokens};
+use crate::token::{self, Delimiter, Nonterminal, Token, TokenKind};
 use crate::AttrVec;
 
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
@@ -23,7 +25,7 @@
 use rustc_span::{Span, DUMMY_SP};
 use smallvec::{smallvec, SmallVec};
 
-use std::{fmt, iter, mem};
+use std::{fmt, iter};
 
 /// When the main Rust parser encounters a syntax-extension invocation, it
 /// parses the arguments to the invocation as a token tree. This is a very
@@ -45,12 +47,6 @@
     Delimited(DelimSpan, Delimiter, TokenStream),
 }
 
-#[derive(Copy, Clone)]
-pub enum CanSynthesizeMissingTokens {
-    Yes,
-    No,
-}
-
 // Ensure all fields of `TokenTree` is `Send` and `Sync`.
 #[cfg(parallel_compiler)]
 fn _dummy()
@@ -146,9 +142,9 @@
 }
 
 impl<S: Encoder> Encodable<S> for LazyTokenStream {
-    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
+    fn encode(&self, s: &mut S) {
         // Used by AST json printing.
-        Encodable::encode(&self.create_token_stream(), s)
+        Encodable::encode(&self.create_token_stream(), s);
     }
 }
 
@@ -403,47 +399,8 @@
         self.0.len()
     }
 
-    pub fn from_streams(mut streams: SmallVec<[TokenStream; 2]>) -> TokenStream {
-        match streams.len() {
-            0 => TokenStream::default(),
-            1 => streams.pop().unwrap(),
-            _ => {
-                // We are going to extend the first stream in `streams` with
-                // the elements from the subsequent streams. This requires
-                // using `make_mut()` on the first stream, and in practice this
-                // doesn't cause cloning 99.9% of the time.
-                //
-                // One very common use case is when `streams` has two elements,
-                // where the first stream has any number of elements within
-                // (often 1, but sometimes many more) and the second stream has
-                // a single element within.
-
-                // Determine how much the first stream will be extended.
-                // Needed to avoid quadratic blow up from on-the-fly
-                // reallocations (#57735).
-                let num_appends = streams.iter().skip(1).map(|ts| ts.len()).sum();
-
-                // Get the first stream. If it's `None`, create an empty
-                // stream.
-                let mut iter = streams.drain(..);
-                let mut first_stream_lrc = iter.next().unwrap().0;
-
-                // Append the elements to the first stream, after reserving
-                // space for them.
-                let first_vec_mut = Lrc::make_mut(&mut first_stream_lrc);
-                first_vec_mut.reserve(num_appends);
-                for stream in iter {
-                    first_vec_mut.extend(stream.0.iter().cloned());
-                }
-
-                // Create the final `TokenStream`.
-                TokenStream(first_stream_lrc)
-            }
-        }
-    }
-
-    pub fn trees(&self) -> Cursor {
-        self.clone().into_trees()
+    pub fn trees(&self) -> CursorRef<'_> {
+        CursorRef::new(self)
     }
 
     pub fn into_trees(self) -> Cursor {
@@ -471,6 +428,89 @@
                 .collect(),
         ))
     }
+
+    fn opt_from_ast(node: &(impl HasAttrs + HasTokens)) -> Option<TokenStream> {
+        let tokens = node.tokens()?;
+        let attrs = node.attrs();
+        let attr_annotated = if attrs.is_empty() {
+            tokens.create_token_stream()
+        } else {
+            let attr_data = AttributesData { attrs: attrs.to_vec().into(), tokens: tokens.clone() };
+            AttrAnnotatedTokenStream::new(vec![(
+                AttrAnnotatedTokenTree::Attributes(attr_data),
+                Spacing::Alone,
+            )])
+        };
+        Some(attr_annotated.to_tokenstream())
+    }
+
+    pub fn from_ast(node: &(impl HasAttrs + HasSpan + HasTokens + fmt::Debug)) -> TokenStream {
+        TokenStream::opt_from_ast(node)
+            .unwrap_or_else(|| panic!("missing tokens for node at {:?}: {:?}", node.span(), node))
+    }
+
+    pub fn from_nonterminal_ast(nt: &Nonterminal) -> TokenStream {
+        match nt {
+            Nonterminal::NtIdent(ident, is_raw) => {
+                TokenTree::token(token::Ident(ident.name, *is_raw), ident.span).into()
+            }
+            Nonterminal::NtLifetime(ident) => {
+                TokenTree::token(token::Lifetime(ident.name), ident.span).into()
+            }
+            Nonterminal::NtItem(item) => TokenStream::from_ast(item),
+            Nonterminal::NtBlock(block) => TokenStream::from_ast(block),
+            Nonterminal::NtStmt(stmt) if let StmtKind::Empty = stmt.kind => {
+                // FIXME: Properly collect tokens for empty statements.
+                TokenTree::token(token::Semi, stmt.span).into()
+            }
+            Nonterminal::NtStmt(stmt) => TokenStream::from_ast(stmt),
+            Nonterminal::NtPat(pat) => TokenStream::from_ast(pat),
+            Nonterminal::NtTy(ty) => TokenStream::from_ast(ty),
+            Nonterminal::NtMeta(attr) => TokenStream::from_ast(attr),
+            Nonterminal::NtPath(path) => TokenStream::from_ast(path),
+            Nonterminal::NtVis(vis) => TokenStream::from_ast(vis),
+            Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => TokenStream::from_ast(expr),
+        }
+    }
+
+    fn flatten_token(token: &Token) -> TokenTree {
+        match &token.kind {
+            token::Interpolated(nt) if let token::NtIdent(ident, is_raw) = **nt => {
+                TokenTree::token(token::Ident(ident.name, is_raw), ident.span)
+            }
+            token::Interpolated(nt) => TokenTree::Delimited(
+                DelimSpan::from_single(token.span),
+                Delimiter::Invisible,
+                TokenStream::from_nonterminal_ast(&nt).flattened(),
+            ),
+            _ => TokenTree::Token(token.clone()),
+        }
+    }
+
+    fn flatten_token_tree(tree: &TokenTree) -> TokenTree {
+        match tree {
+            TokenTree::Token(token) => TokenStream::flatten_token(token),
+            TokenTree::Delimited(span, delim, tts) => {
+                TokenTree::Delimited(*span, *delim, tts.flattened())
+            }
+        }
+    }
+
+    #[must_use]
+    pub fn flattened(&self) -> TokenStream {
+        fn can_skip(stream: &TokenStream) -> bool {
+            stream.trees().all(|tree| match tree {
+                TokenTree::Token(token) => !matches!(token.kind, token::Interpolated(_)),
+                TokenTree::Delimited(_, _, inner) => can_skip(inner),
+            })
+        }
+
+        if can_skip(self) {
+            return self.clone();
+        }
+
+        self.trees().map(|tree| TokenStream::flatten_token_tree(tree)).collect()
+    }
 }
 
 // 99.5%+ of the time we have 1 or 2 elements in this vector.
@@ -483,50 +523,65 @@
     }
 
     pub fn push<T: Into<TokenStream>>(&mut self, stream: T) {
-        let mut stream = stream.into();
-
-        // If `self` is not empty and the last tree within the last stream is a
-        // token tree marked with `Joint`...
-        if let Some(TokenStream(ref mut last_stream_lrc)) = self.0.last_mut()
-            && let Some((TokenTree::Token(last_token), Spacing::Joint)) = last_stream_lrc.last()
-            // ...and `stream` is not empty and the first tree within it is
-            // a token tree...
-            && let TokenStream(ref mut stream_lrc) = stream
-            && let Some((TokenTree::Token(token), spacing)) = stream_lrc.first()
-            // ...and the two tokens can be glued together...
-            && let Some(glued_tok) = last_token.glue(&token)
-        {
-            // ...then do so, by overwriting the last token
-            // tree in `self` and removing the first token tree
-            // from `stream`. This requires using `make_mut()`
-            // on the last stream in `self` and on `stream`,
-            // and in practice this doesn't cause cloning 99.9%
-            // of the time.
-
-            // Overwrite the last token tree with the merged
-            // token.
-            let last_vec_mut = Lrc::make_mut(last_stream_lrc);
-            *last_vec_mut.last_mut().unwrap() = (TokenTree::Token(glued_tok), *spacing);
-
-            // Remove the first token tree from `stream`. (This
-            // is almost always the only tree in `stream`.)
-            let stream_vec_mut = Lrc::make_mut(stream_lrc);
-            stream_vec_mut.remove(0);
-
-            // Don't push `stream` if it's empty -- that could
-            // block subsequent token gluing, by getting
-            // between two token trees that should be glued
-            // together.
-            if !stream.is_empty() {
-                self.0.push(stream);
-            }
-            return;
-        }
-        self.0.push(stream);
+        self.0.push(stream.into());
     }
 
     pub fn build(self) -> TokenStream {
-        TokenStream::from_streams(self.0)
+        let mut streams = self.0;
+        match streams.len() {
+            0 => TokenStream::default(),
+            1 => streams.pop().unwrap(),
+            _ => {
+                // We will extend the first stream in `streams` with the
+                // elements from the subsequent streams. This requires using
+                // `make_mut()` on the first stream, and in practice this
+                // doesn't cause cloning 99.9% of the time.
+                //
+                // One very common use case is when `streams` has two elements,
+                // where the first stream has any number of elements within
+                // (often 1, but sometimes many more) and the second stream has
+                // a single element within.
+
+                // Determine how much the first stream will be extended.
+                // Needed to avoid quadratic blow up from on-the-fly
+                // reallocations (#57735).
+                let num_appends = streams.iter().skip(1).map(|ts| ts.len()).sum();
+
+                // Get the first stream, which will become the result stream.
+                // If it's `None`, create an empty stream.
+                let mut iter = streams.drain(..);
+                let mut res_stream_lrc = iter.next().unwrap().0;
+
+                // Append the subsequent elements to the result stream, after
+                // reserving space for them.
+                let res_vec_mut = Lrc::make_mut(&mut res_stream_lrc);
+                res_vec_mut.reserve(num_appends);
+                for stream in iter {
+                    let stream_iter = stream.0.iter().cloned();
+
+                    // If (a) `res_mut_vec` is not empty and the last tree
+                    // within it is a token tree marked with `Joint`, and (b)
+                    // `stream` is not empty and the first tree within it is a
+                    // token tree, and (c) the two tokens can be glued
+                    // together...
+                    if let Some((TokenTree::Token(last_tok), Spacing::Joint)) = res_vec_mut.last()
+                        && let Some((TokenTree::Token(tok), spacing)) = stream.0.first()
+                        && let Some(glued_tok) = last_tok.glue(&tok)
+                    {
+                        // ...then overwrite the last token tree in
+                        // `res_vec_mut` with the glued token, and skip the
+                        // first token tree from `stream`.
+                        *res_vec_mut.last_mut().unwrap() = (TokenTree::Token(glued_tok), *spacing);
+                        res_vec_mut.extend(stream_iter.skip(1));
+                    } else {
+                        // Append all of `stream`.
+                        res_vec_mut.extend(stream_iter);
+                    }
+                }
+
+                TokenStream(res_stream_lrc)
+            }
+        }
     }
 }
 
@@ -538,12 +593,21 @@
 }
 
 impl<'t> CursorRef<'t> {
+    fn new(stream: &'t TokenStream) -> Self {
+        CursorRef { stream, index: 0 }
+    }
+
+    #[inline]
     fn next_with_spacing(&mut self) -> Option<&'t TreeAndSpacing> {
         self.stream.0.get(self.index).map(|tree| {
             self.index += 1;
             tree
         })
     }
+
+    pub fn look_ahead(&self, n: usize) -> Option<&TokenTree> {
+        self.stream.0[self.index..].get(n).map(|(tree, _)| tree)
+    }
 }
 
 impl<'t> Iterator for CursorRef<'t> {
@@ -591,20 +655,6 @@
         })
     }
 
-    pub fn index(&self) -> usize {
-        self.index
-    }
-
-    pub fn append(&mut self, new_stream: TokenStream) {
-        if new_stream.is_empty() {
-            return;
-        }
-        let index = self.index;
-        let stream = mem::take(&mut self.stream);
-        *self = TokenStream::from_streams(smallvec![stream, new_stream]).into_trees();
-        self.index = index;
-    }
-
     pub fn look_ahead(&self, n: usize) -> Option<&TokenTree> {
         self.stream.0[self.index..].get(n).map(|(tree, _)| tree)
     }
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs
index cc772ac..2ce8590 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -89,6 +89,16 @@
     }
 }
 
+#[derive(Copy, Clone, Debug)]
+pub enum LifetimeCtxt {
+    /// Appears in a reference type.
+    Rptr,
+    /// Appears as a bound on a type or another lifetime.
+    Bound,
+    /// Appears as a generic argument.
+    GenericArg,
+}
+
 /// Each method of the `Visitor` trait is a hook to be potentially
 /// overridden. Each method's default implementation recursively visits
 /// the substructure of the input via the corresponding `walk` method;
@@ -184,7 +194,7 @@
     fn visit_label(&mut self, label: &'ast Label) {
         walk_label(self, label)
     }
-    fn visit_lifetime(&mut self, lifetime: &'ast Lifetime) {
+    fn visit_lifetime(&mut self, lifetime: &'ast Lifetime, _: LifetimeCtxt) {
         walk_lifetime(self, lifetime)
     }
     fn visit_mac_call(&mut self, mac: &'ast MacCall) {
@@ -326,7 +336,7 @@
         ItemKind::ForeignMod(ref foreign_module) => {
             walk_list!(visitor, visit_foreign_item, &foreign_module.items);
         }
-        ItemKind::GlobalAsm(ref asm) => walk_inline_asm(visitor, asm),
+        ItemKind::GlobalAsm(ref asm) => visitor.visit_inline_asm(asm),
         ItemKind::TyAlias(box TyAlias { ref generics, ref bounds, ref ty, .. }) => {
             visitor.visit_generics(generics);
             walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound);
@@ -414,7 +424,7 @@
         TyKind::Slice(ref ty) | TyKind::Paren(ref ty) => visitor.visit_ty(ty),
         TyKind::Ptr(ref mutable_type) => visitor.visit_ty(&mutable_type.ty),
         TyKind::Rptr(ref opt_lifetime, ref mutable_type) => {
-            walk_list!(visitor, visit_lifetime, opt_lifetime);
+            walk_list!(visitor, visit_lifetime, opt_lifetime, LifetimeCtxt::Rptr);
             visitor.visit_ty(&mutable_type.ty)
         }
         TyKind::Tup(ref tuple_element_types) => {
@@ -507,7 +517,7 @@
     V: Visitor<'a>,
 {
     match generic_arg {
-        GenericArg::Lifetime(lt) => visitor.visit_lifetime(lt),
+        GenericArg::Lifetime(lt) => visitor.visit_lifetime(lt, LifetimeCtxt::GenericArg),
         GenericArg::Type(ty) => visitor.visit_ty(ty),
         GenericArg::Const(ct) => visitor.visit_anon_const(ct),
     }
@@ -599,7 +609,9 @@
 pub fn walk_param_bound<'a, V: Visitor<'a>>(visitor: &mut V, bound: &'a GenericBound) {
     match *bound {
         GenericBound::Trait(ref typ, ref modifier) => visitor.visit_poly_trait_ref(typ, modifier),
-        GenericBound::Outlives(ref lifetime) => visitor.visit_lifetime(lifetime),
+        GenericBound::Outlives(ref lifetime) => {
+            visitor.visit_lifetime(lifetime, LifetimeCtxt::Bound)
+        }
     }
 }
 
@@ -639,7 +651,7 @@
         WherePredicate::RegionPredicate(WhereRegionPredicate {
             ref lifetime, ref bounds, ..
         }) => {
-            visitor.visit_lifetime(lifetime);
+            visitor.visit_lifetime(lifetime, LifetimeCtxt::Bound);
             walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound);
         }
         WherePredicate::EqPredicate(WhereEqPredicate { ref lhs_ty, ref rhs_ty, .. }) => {
@@ -897,7 +909,7 @@
         }
         ExprKind::MacCall(ref mac) => visitor.visit_mac_call(mac),
         ExprKind::Paren(ref subexpression) => visitor.visit_expr(subexpression),
-        ExprKind::InlineAsm(ref asm) => walk_inline_asm(visitor, asm),
+        ExprKind::InlineAsm(ref asm) => visitor.visit_inline_asm(asm),
         ExprKind::Yield(ref optional_expression) => {
             walk_list!(visitor, visit_expr, optional_expression);
         }
diff --git a/compiler/rustc_ast_lowering/Cargo.toml b/compiler/rustc_ast_lowering/Cargo.toml
index 7989af2..e344d8a 100644
--- a/compiler/rustc_ast_lowering/Cargo.toml
+++ b/compiler/rustc_ast_lowering/Cargo.toml
@@ -14,6 +14,7 @@
 rustc_target = { path = "../rustc_target" }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_index = { path = "../rustc_index" }
+rustc_middle = { path = "../rustc_middle" }
 rustc_query_system = { path = "../rustc_query_system" }
 rustc_span = { path = "../rustc_span" }
 rustc_errors = { path = "../rustc_errors" }
diff --git a/compiler/rustc_ast_lowering/src/asm.rs b/compiler/rustc_ast_lowering/src/asm.rs
index ae3e367..aab9b90 100644
--- a/compiler/rustc_ast_lowering/src/asm.rs
+++ b/compiler/rustc_ast_lowering/src/asm.rs
@@ -1,4 +1,4 @@
-use crate::{ImplTraitContext, ImplTraitPosition, ParamMode};
+use crate::{ImplTraitContext, ImplTraitPosition, ParamMode, ResolverAstLoweringExt};
 
 use super::LoweringContext;
 
@@ -11,13 +11,17 @@
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::definitions::DefPathData;
 use rustc_session::parse::feature_err;
-use rustc_span::{sym, ExpnId, Span};
+use rustc_span::{sym, Span};
 use rustc_target::asm;
 use std::collections::hash_map::Entry;
 use std::fmt::Write;
 
 impl<'a, 'hir> LoweringContext<'a, 'hir> {
-    crate fn lower_inline_asm(&mut self, sp: Span, asm: &InlineAsm) -> &'hir hir::InlineAsm<'hir> {
+    pub(crate) fn lower_inline_asm(
+        &mut self,
+        sp: Span,
+        asm: &InlineAsm,
+    ) -> &'hir hir::InlineAsm<'hir> {
         // Rustdoc needs to support asm! from foreign architectures: don't try
         // lowering the register constraints in this case.
         let asm_arch = if self.sess.opts.actually_rustdoc { None } else { self.sess.asm_arch };
@@ -238,14 +242,8 @@
 
                             // Wrap the expression in an AnonConst.
                             let parent_def_id = self.current_hir_id_owner;
-                            let node_id = self.resolver.next_node_id();
-                            self.resolver.create_def(
-                                parent_def_id,
-                                node_id,
-                                DefPathData::AnonConst,
-                                ExpnId::root(),
-                                *op_sp,
-                            );
+                            let node_id = self.next_node_id();
+                            self.create_def(parent_def_id, node_id, DefPathData::AnonConst);
                             let anon_const = AnonConst { id: node_id, value: P(expr) };
                             hir::InlineAsmOperand::SymFn {
                                 anon_const: self.lower_anon_const(&anon_const),
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index 410ed3f..3babe73 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -1,6 +1,6 @@
-use crate::{FnDeclKind, ImplTraitPosition};
-
+use super::ResolverAstLoweringExt;
 use super::{ImplTraitContext, LoweringContext, ParamMode, ParenthesizedGenericArgs};
+use crate::{FnDeclKind, ImplTraitPosition};
 
 use rustc_ast::attr;
 use rustc_ast::ptr::P as AstP;
@@ -11,7 +11,6 @@
 use rustc_hir as hir;
 use rustc_hir::def::Res;
 use rustc_hir::definitions::DefPathData;
-use rustc_span::hygiene::ExpnId;
 use rustc_span::source_map::{respan, DesugaringKind, Span, Spanned};
 use rustc_span::symbol::{sym, Ident};
 use rustc_span::DUMMY_SP;
@@ -41,7 +40,22 @@
                 }
                 ExprKind::Tup(ref elts) => hir::ExprKind::Tup(self.lower_exprs(elts)),
                 ExprKind::Call(ref f, ref args) => {
-                    if let Some(legacy_args) = self.resolver.legacy_const_generic_args(f) {
+                    if e.attrs.get(0).map_or(false, |a| a.has_name(sym::rustc_box)) {
+                        if let [inner] = &args[..] && e.attrs.len() == 1 {
+                            let kind = hir::ExprKind::Box(self.lower_expr(&inner));
+                            let hir_id = self.lower_node_id(e.id);
+                            return hir::Expr { hir_id, kind, span: self.lower_span(e.span) };
+                        } else {
+                            self.sess
+                                .struct_span_err(
+                                    e.span,
+                                    "#[rustc_box] requires precisely one argument \
+                                    and no other attributes are allowed",
+                                )
+                                .emit();
+                            hir::ExprKind::Err
+                        }
+                    } else if let Some(legacy_args) = self.resolver.legacy_const_generic_args(f) {
                         self.lower_legacy_const_generics((**f).clone(), args.clone(), &legacy_args)
                     } else {
                         let f = self.lower_expr(f);
@@ -151,6 +165,7 @@
                     if let Async::Yes { closure_id, .. } = asyncness {
                         self.lower_expr_async_closure(
                             capture_clause,
+                            e.id,
                             closure_id,
                             decl,
                             body,
@@ -159,6 +174,7 @@
                     } else {
                         self.lower_expr_closure(
                             capture_clause,
+                            e.id,
                             movability,
                             decl,
                             body,
@@ -340,16 +356,10 @@
         for (idx, arg) in args.into_iter().enumerate() {
             if legacy_args_idx.contains(&idx) {
                 let parent_def_id = self.current_hir_id_owner;
-                let node_id = self.resolver.next_node_id();
+                let node_id = self.next_node_id();
 
                 // Add a definition for the in-band const def.
-                self.resolver.create_def(
-                    parent_def_id,
-                    node_id,
-                    DefPathData::AnonConst,
-                    ExpnId::root(),
-                    arg.span,
-                );
+                self.create_def(parent_def_id, node_id, DefPathData::AnonConst);
 
                 let anon_const = AnonConst { id: node_id, value: arg };
                 generic_args.push(AngleBracketedArg::Arg(GenericArg::Const(anon_const)));
@@ -505,8 +515,14 @@
     fn lower_arm(&mut self, arm: &Arm) -> hir::Arm<'hir> {
         let pat = self.lower_pat(&arm.pat);
         let guard = arm.guard.as_ref().map(|cond| {
-            if let ExprKind::Let(ref pat, ref scrutinee, _) = cond.kind {
-                hir::Guard::IfLet(self.lower_pat(pat), self.lower_expr(scrutinee))
+            if let ExprKind::Let(ref pat, ref scrutinee, span) = cond.kind {
+                hir::Guard::IfLet(self.arena.alloc(hir::Let {
+                    hir_id: self.next_id(),
+                    span: self.lower_span(span),
+                    pat: self.lower_pat(pat),
+                    ty: None,
+                    init: self.lower_expr(scrutinee),
+                }))
             } else {
                 hir::Guard::If(self.lower_expr(cond))
             }
@@ -556,7 +572,7 @@
         };
 
         // The closure/generator `FnDecl` takes a single (resume) argument of type `input_ty`.
-        let decl = self.arena.alloc(hir::FnDecl {
+        let fn_decl = self.arena.alloc(hir::FnDecl {
             inputs: arena_vec![self; input_ty],
             output,
             c_variadic: false,
@@ -577,7 +593,7 @@
         };
         let params = arena_vec![self; param];
 
-        let body_id = self.lower_body(move |this| {
+        let body = self.lower_body(move |this| {
             this.generator_kind = Some(hir::GeneratorKind::Async(async_gen_kind));
 
             let old_ctx = this.task_context;
@@ -588,13 +604,14 @@
         });
 
         // `static |_task_context| -> <ret_ty> { body }`:
-        let generator_kind = hir::ExprKind::Closure(
+        let generator_kind = hir::ExprKind::Closure {
             capture_clause,
-            decl,
-            body_id,
-            self.lower_span(span),
-            Some(hir::Movability::Static),
-        );
+            bound_generic_params: &[],
+            fn_decl,
+            body,
+            fn_decl_span: self.lower_span(span),
+            movability: Some(hir::Movability::Static),
+        };
         let generator = hir::Expr {
             hir_id: self.lower_node_id(closure_node_id),
             kind: generator_kind,
@@ -703,7 +720,7 @@
         };
 
         // `::std::task::Poll::Ready(result) => break result`
-        let loop_node_id = self.resolver.next_node_id();
+        let loop_node_id = self.next_node_id();
         let loop_hir_id = self.lower_node_id(loop_node_id);
         let ready_arm = {
             let x_ident = Ident::with_dummy_span(sym::result);
@@ -814,12 +831,13 @@
     fn lower_expr_closure(
         &mut self,
         capture_clause: CaptureBy,
+        closure_id: NodeId,
         movability: Movability,
         decl: &FnDecl,
         body: &Expr,
         fn_decl_span: Span,
     ) -> hir::ExprKind<'hir> {
-        let (body_id, generator_option) = self.with_new_scopes(move |this| {
+        let (body, generator_option) = self.with_new_scopes(move |this| {
             let prev = this.current_item;
             this.current_item = Some(fn_decl_span);
             let mut generator_kind = None;
@@ -834,16 +852,19 @@
             (body_id, generator_option)
         });
 
-        // Lower outside new scope to preserve `is_in_loop_condition`.
-        let fn_decl = self.lower_fn_decl(decl, None, FnDeclKind::Closure, None);
+        self.with_lifetime_binder(closure_id, &[], |this, bound_generic_params| {
+            // Lower outside new scope to preserve `is_in_loop_condition`.
+            let fn_decl = this.lower_fn_decl(decl, None, FnDeclKind::Closure, None);
 
-        hir::ExprKind::Closure(
-            capture_clause,
-            fn_decl,
-            body_id,
-            self.lower_span(fn_decl_span),
-            generator_option,
-        )
+            hir::ExprKind::Closure {
+                capture_clause,
+                bound_generic_params,
+                fn_decl,
+                body,
+                fn_decl_span: this.lower_span(fn_decl_span),
+                movability: generator_option,
+            }
+        })
     }
 
     fn generator_movability_for_fn(
@@ -883,6 +904,7 @@
         &mut self,
         capture_clause: CaptureBy,
         closure_id: NodeId,
+        inner_closure_id: NodeId,
         decl: &FnDecl,
         body: &Expr,
         fn_decl_span: Span,
@@ -890,7 +912,7 @@
         let outer_decl =
             FnDecl { inputs: decl.inputs.clone(), output: FnRetTy::Default(fn_decl_span) };
 
-        let body_id = self.with_new_scopes(|this| {
+        let body = self.with_new_scopes(|this| {
             // FIXME(cramertj): allow `async` non-`move` closures with arguments.
             if capture_clause == CaptureBy::Ref && !decl.inputs.is_empty() {
                 struct_span_err!(
@@ -913,7 +935,7 @@
                     if let FnRetTy::Ty(ty) = &decl.output { Some(ty.clone()) } else { None };
                 let async_body = this.make_async_expr(
                     capture_clause,
-                    closure_id,
+                    inner_closure_id,
                     async_ret_ty,
                     body.span,
                     hir::AsyncGeneratorKind::Closure,
@@ -924,18 +946,21 @@
             body_id
         });
 
-        // We need to lower the declaration outside the new scope, because we
-        // have to conserve the state of being inside a loop condition for the
-        // closure argument types.
-        let fn_decl = self.lower_fn_decl(&outer_decl, None, FnDeclKind::Closure, None);
+        self.with_lifetime_binder(closure_id, &[], |this, bound_generic_params| {
+            // We need to lower the declaration outside the new scope, because we
+            // have to conserve the state of being inside a loop condition for the
+            // closure argument types.
+            let fn_decl = this.lower_fn_decl(&outer_decl, None, FnDeclKind::Closure, None);
 
-        hir::ExprKind::Closure(
-            capture_clause,
-            fn_decl,
-            body_id,
-            self.lower_span(fn_decl_span),
-            None,
-        )
+            hir::ExprKind::Closure {
+                capture_clause,
+                bound_generic_params,
+                fn_decl,
+                body,
+                fn_decl_span: this.lower_span(fn_decl_span),
+                movability: None,
+            }
+        })
     }
 
     /// Destructure the LHS of complex assignments.
@@ -1147,7 +1172,7 @@
                             .span_suggestion(
                                 e.span,
                                 "consider removing the trailing pattern",
-                                String::new(),
+                                "",
                                 rustc_errors::Applicability::MachineApplicable,
                             )
                             .emit();
diff --git a/compiler/rustc_ast_lowering/src/index.rs b/compiler/rustc_ast_lowering/src/index.rs
index c506360..4be2202 100644
--- a/compiler/rustc_ast_lowering/src/index.rs
+++ b/compiler/rustc_ast_lowering/src/index.rs
@@ -6,6 +6,7 @@
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::*;
 use rustc_index::vec::{Idx, IndexVec};
+use rustc_middle::span_bug;
 use rustc_session::Session;
 use rustc_span::source_map::SourceMap;
 use rustc_span::{Span, DUMMY_SP};
@@ -75,7 +76,8 @@
         // owner of that node.
         if cfg!(debug_assertions) {
             if hir_id.owner != self.owner {
-                panic!(
+                span_bug!(
+                    span,
                     "inconsistent DepNode at `{:?}` for `{:?}`: \
                      current_dep_node_owner={} ({:?}), hir_id.owner={} ({:?})",
                     self.source_map.span_to_diagnostic_string(span),
@@ -313,6 +315,13 @@
         });
     }
 
+    fn visit_assoc_type_binding(&mut self, type_binding: &'hir TypeBinding<'hir>) {
+        self.insert(type_binding.span, type_binding.hir_id, Node::TypeBinding(type_binding));
+        self.with_parent(type_binding.hir_id, |this| {
+            intravisit::walk_assoc_type_binding(this, type_binding)
+        })
+    }
+
     fn visit_trait_item_ref(&mut self, ii: &'hir TraitItemRef) {
         // Do not visit the duplicate information in TraitItemRef. We want to
         // map the actual nodes, not the duplicate ones in the *Ref.
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index cf97b27..0ef2137 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -1,4 +1,5 @@
-use super::{AstOwner, ImplTraitContext, ImplTraitPosition, ResolverAstLowering};
+use super::ResolverAstLoweringExt;
+use super::{AstOwner, ImplTraitContext, ImplTraitPosition};
 use super::{LoweringContext, ParamMode};
 use crate::{Arena, FnDeclKind};
 
@@ -11,23 +12,26 @@
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
+use rustc_hir::definitions::Definitions;
 use rustc_hir::PredicateOrigin;
 use rustc_index::vec::{Idx, IndexVec};
-use rustc_session::utils::NtToTokenstream;
+use rustc_middle::ty::{ResolverAstLowering, ResolverOutputs};
+use rustc_session::cstore::CrateStoreDyn;
 use rustc_session::Session;
 use rustc_span::source_map::DesugaringKind;
 use rustc_span::symbol::{kw, sym, Ident};
 use rustc_span::Span;
 use rustc_target::spec::abi;
 use smallvec::{smallvec, SmallVec};
-use tracing::debug;
 
 use std::iter;
 
 pub(super) struct ItemLowerer<'a, 'hir> {
     pub(super) sess: &'a Session,
-    pub(super) resolver: &'a mut dyn ResolverAstLowering,
-    pub(super) nt_to_tokenstream: NtToTokenstream,
+    pub(super) definitions: &'a mut Definitions,
+    pub(super) cstore: &'a CrateStoreDyn,
+    pub(super) resolutions: &'a ResolverOutputs,
+    pub(super) resolver: &'a mut ResolverAstLowering,
     pub(super) arena: &'hir Arena<'hir>,
     pub(super) ast_index: &'a IndexVec<LocalDefId, AstOwner<'a>>,
     pub(super) owners: &'a mut IndexVec<LocalDefId, hir::MaybeOwner<&'hir hir::OwnerInfo<'hir>>>,
@@ -62,8 +66,10 @@
         let mut lctx = LoweringContext {
             // Pseudo-globals.
             sess: &self.sess,
+            definitions: self.definitions,
+            cstore: self.cstore,
+            resolutions: self.resolutions,
             resolver: self.resolver,
-            nt_to_tokenstream: self.nt_to_tokenstream,
             arena: self.arena,
 
             // HirId handling.
@@ -86,6 +92,8 @@
             task_context: None,
             current_item: None,
             captured_lifetimes: None,
+            impl_trait_defs: Vec::new(),
+            impl_trait_bounds: Vec::new(),
             allow_try_trait: Some([sym::try_trait_v2, sym::yeet_desugar_details][..].into()),
             allow_gen_future: Some([sym::gen_future][..].into()),
             allow_into_future: Some([sym::into_future][..].into()),
@@ -118,9 +126,9 @@
         self.owners[def_id]
     }
 
+    #[instrument(level = "debug", skip(self, c))]
     fn lower_crate(&mut self, c: &Crate) {
-        debug_assert_eq!(self.resolver.local_def_id(CRATE_NODE_ID), CRATE_DEF_ID);
-
+        debug_assert_eq!(self.resolver.node_id_to_def_id[&CRATE_NODE_ID], CRATE_DEF_ID);
         self.with_lctx(CRATE_NODE_ID, |lctx| {
             let module = lctx.lower_mod(&c.items, &c.spans);
             lctx.lower_attrs(hir::CRATE_HIR_ID, &c.attrs);
@@ -128,15 +136,16 @@
         })
     }
 
+    #[instrument(level = "debug", skip(self))]
     fn lower_item(&mut self, item: &Item) {
         self.with_lctx(item.id, |lctx| hir::OwnerNode::Item(lctx.lower_item(item)))
     }
 
     fn lower_assoc_item(&mut self, item: &AssocItem, ctxt: AssocCtxt) {
-        let def_id = self.resolver.local_def_id(item.id);
+        let def_id = self.resolver.node_id_to_def_id[&item.id];
 
         let parent_id = {
-            let parent = self.resolver.definitions().def_key(def_id).parent;
+            let parent = self.definitions.def_key(def_id).parent;
             let local_def_index = parent.unwrap();
             LocalDefId { local_def_index }
         };
@@ -177,7 +186,7 @@
     }
 
     pub(super) fn lower_item_ref(&mut self, i: &Item) -> SmallVec<[hir::ItemId; 1]> {
-        let mut node_ids = smallvec![hir::ItemId { def_id: self.resolver.local_def_id(i.id) }];
+        let mut node_ids = smallvec![hir::ItemId { def_id: self.local_def_id(i.id) }];
         if let ItemKind::Use(ref use_tree) = &i.kind {
             self.lower_item_id_use_tree(use_tree, i.id, &mut node_ids);
         }
@@ -193,7 +202,7 @@
         match tree.kind {
             UseTreeKind::Nested(ref nested_vec) => {
                 for &(ref nested, id) in nested_vec {
-                    vec.push(hir::ItemId { def_id: self.resolver.local_def_id(id) });
+                    vec.push(hir::ItemId { def_id: self.local_def_id(id) });
                     self.lower_item_id_use_tree(nested, id, vec);
                 }
             }
@@ -202,7 +211,7 @@
                 for (_, &id) in
                     iter::zip(self.expect_full_res_from_use(base_id).skip(1), &[id1, id2])
                 {
-                    vec.push(hir::ItemId { def_id: self.resolver.local_def_id(id) });
+                    vec.push(hir::ItemId { def_id: self.local_def_id(id) });
                 }
             }
         }
@@ -267,16 +276,11 @@
                     let body_id =
                         this.lower_maybe_async_body(span, &decl, asyncness, body.as_deref());
 
-                    let (generics, decl) =
-                        this.add_implicit_generics(generics, id, |this, idty, idpb| {
-                            let ret_id = asyncness.opt_return_id();
-                            this.lower_fn_decl(
-                                &decl,
-                                Some((id, idty, idpb)),
-                                FnDeclKind::Fn,
-                                ret_id,
-                            )
-                        });
+                    let itctx = ImplTraitContext::Universal;
+                    let (generics, decl) = this.lower_generics(generics, id, itctx, |this| {
+                        let ret_id = asyncness.opt_return_id();
+                        this.lower_fn_decl(&decl, Some(id), FnDeclKind::Fn, ret_id)
+                    });
                     let sig = hir::FnSig {
                         decl,
                         header: this.lower_fn_header(header),
@@ -314,57 +318,59 @@
                 //
                 // type Foo = Foo1
                 // opaque type Foo1: Trait
-                let ty = self.lower_ty(ty, ImplTraitContext::TypeAliasesOpaqueTy);
                 let mut generics = generics.clone();
                 add_ty_alias_where_clause(&mut generics, where_clauses, true);
-                let generics = self.lower_generics(
+                let (generics, ty) = self.lower_generics(
                     &generics,
+                    id,
                     ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
+                    |this| this.lower_ty(ty, ImplTraitContext::TypeAliasesOpaqueTy),
                 );
                 hir::ItemKind::TyAlias(ty, generics)
             }
             ItemKind::TyAlias(box TyAlias {
                 ref generics, ref where_clauses, ty: None, ..
             }) => {
-                let ty = self.arena.alloc(self.ty(span, hir::TyKind::Err));
                 let mut generics = generics.clone();
                 add_ty_alias_where_clause(&mut generics, *where_clauses, true);
-                let generics = self.lower_generics(
+                let (generics, ty) = self.lower_generics(
                     &generics,
+                    id,
                     ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
+                    |this| this.arena.alloc(this.ty(span, hir::TyKind::Err)),
                 );
                 hir::ItemKind::TyAlias(ty, generics)
             }
-            ItemKind::Enum(ref enum_definition, ref generics) => hir::ItemKind::Enum(
-                hir::EnumDef {
-                    variants: self.arena.alloc_from_iter(
-                        enum_definition.variants.iter().map(|x| self.lower_variant(x)),
-                    ),
-                },
-                self.lower_generics(
+            ItemKind::Enum(ref enum_definition, ref generics) => {
+                let (generics, variants) = self.lower_generics(
                     generics,
+                    id,
                     ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
-                ),
-            ),
+                    |this| {
+                        this.arena.alloc_from_iter(
+                            enum_definition.variants.iter().map(|x| this.lower_variant(x)),
+                        )
+                    },
+                );
+                hir::ItemKind::Enum(hir::EnumDef { variants }, generics)
+            }
             ItemKind::Struct(ref struct_def, ref generics) => {
-                let struct_def = self.lower_variant_data(hir_id, struct_def);
-                hir::ItemKind::Struct(
-                    struct_def,
-                    self.lower_generics(
-                        generics,
-                        ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
-                    ),
-                )
+                let (generics, struct_def) = self.lower_generics(
+                    generics,
+                    id,
+                    ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
+                    |this| this.lower_variant_data(hir_id, struct_def),
+                );
+                hir::ItemKind::Struct(struct_def, generics)
             }
             ItemKind::Union(ref vdata, ref generics) => {
-                let vdata = self.lower_variant_data(hir_id, vdata);
-                hir::ItemKind::Union(
-                    vdata,
-                    self.lower_generics(
-                        generics,
-                        ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
-                    ),
-                )
+                let (generics, vdata) = self.lower_generics(
+                    generics,
+                    id,
+                    ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
+                    |this| this.lower_variant_data(hir_id, vdata),
+                );
+                hir::ItemKind::Union(vdata, generics)
             }
             ItemKind::Impl(box Impl {
                 unsafety,
@@ -389,8 +395,9 @@
                 // method, it will not be considered an in-band
                 // lifetime to be added, but rather a reference to a
                 // parent lifetime.
+                let itctx = ImplTraitContext::Universal;
                 let (generics, (trait_ref, lowered_ty)) =
-                    self.add_implicit_generics(ast_generics, id, |this, _, _| {
+                    self.lower_generics(ast_generics, id, itctx, |this| {
                         let trait_ref = trait_ref.as_ref().map(|trait_ref| {
                             this.lower_trait_ref(
                                 trait_ref,
@@ -435,37 +442,41 @@
                 ref bounds,
                 ref items,
             }) => {
-                let bounds = self.lower_param_bounds(
-                    bounds,
-                    ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
-                );
-                let items = self
-                    .arena
-                    .alloc_from_iter(items.iter().map(|item| self.lower_trait_item_ref(item)));
-                hir::ItemKind::Trait(
-                    is_auto,
-                    self.lower_unsafety(unsafety),
-                    self.lower_generics(
-                        generics,
-                        ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
-                    ),
-                    bounds,
-                    items,
-                )
-            }
-            ItemKind::TraitAlias(ref generics, ref bounds) => hir::ItemKind::TraitAlias(
-                self.lower_generics(
+                let (generics, (unsafety, items, bounds)) = self.lower_generics(
                     generics,
+                    id,
                     ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
-                ),
-                self.lower_param_bounds(
-                    bounds,
-                    ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
-                ),
-            ),
+                    |this| {
+                        let bounds = this.lower_param_bounds(
+                            bounds,
+                            ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
+                        );
+                        let items = this.arena.alloc_from_iter(
+                            items.iter().map(|item| this.lower_trait_item_ref(item)),
+                        );
+                        let unsafety = this.lower_unsafety(unsafety);
+                        (unsafety, items, bounds)
+                    },
+                );
+                hir::ItemKind::Trait(is_auto, unsafety, generics, bounds, items)
+            }
+            ItemKind::TraitAlias(ref generics, ref bounds) => {
+                let (generics, bounds) = self.lower_generics(
+                    generics,
+                    id,
+                    ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
+                    |this| {
+                        this.lower_param_bounds(
+                            bounds,
+                            ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
+                        )
+                    },
+                );
+                hir::ItemKind::TraitAlias(generics, bounds)
+            }
             ItemKind::MacroDef(MacroDef { ref body, macro_rules }) => {
                 let body = P(self.lower_mac_args(body));
-                let macro_kind = self.resolver.decl_macro_kind(self.resolver.local_def_id(id));
+                let macro_kind = self.resolver.decl_macro_kind(self.local_def_id(id));
                 hir::ItemKind::Macro(ast::MacroDef { body, macro_rules }, macro_kind)
             }
             ItemKind::MacCall(..) => {
@@ -484,6 +495,7 @@
         (ty, self.lower_const_body(span, body))
     }
 
+    #[instrument(level = "debug", skip(self))]
     fn lower_use_tree(
         &mut self,
         tree: &UseTree,
@@ -493,8 +505,6 @@
         ident: &mut Ident,
         attrs: Option<&'hir [Attribute]>,
     ) -> hir::ItemKind<'hir> {
-        debug!("lower_use_tree(tree={:?})", tree);
-
         let path = &tree.prefix;
         let segments = prefix.segments.iter().chain(path.segments.iter()).cloned().collect();
 
@@ -526,7 +536,7 @@
                 // Essentially a single `use` which imports two names is desugared into
                 // two imports.
                 for new_node_id in [id1, id2] {
-                    let new_id = self.resolver.local_def_id(new_node_id);
+                    let new_id = self.local_def_id(new_node_id);
                     let Some(res) = resolutions.next() else {
                         // Associate an HirId to both ids even if there is no resolution.
                         let _old = self.children.insert(
@@ -539,7 +549,7 @@
                     let ident = *ident;
                     let mut path = path.clone();
                     for seg in &mut path.segments {
-                        seg.id = self.resolver.next_node_id();
+                        seg.id = self.next_node_id();
                     }
                     let span = path.span;
 
@@ -602,13 +612,13 @@
 
                 // Add all the nested `PathListItem`s to the HIR.
                 for &(ref use_tree, id) in trees {
-                    let new_hir_id = self.resolver.local_def_id(id);
+                    let new_hir_id = self.local_def_id(id);
 
                     let mut prefix = prefix.clone();
 
                     // Give the segments new node-ids since they are being cloned.
                     for seg in &mut prefix.segments {
-                        seg.id = self.resolver.next_node_id();
+                        seg.id = self.next_node_id();
                     }
 
                     // Each `use` import is an item and thus are owners of the
@@ -654,8 +664,9 @@
             kind: match i.kind {
                 ForeignItemKind::Fn(box Fn { ref sig, ref generics, .. }) => {
                     let fdec = &sig.decl;
+                    let itctx = ImplTraitContext::Universal;
                     let (generics, (fn_dec, fn_args)) =
-                        self.add_implicit_generics(generics, i.id, |this, _, _| {
+                        self.lower_generics(generics, i.id, itctx, |this| {
                             (
                                 // Disallow `impl Trait` in foreign items.
                                 this.lower_fn_decl(fdec, None, FnDeclKind::ExternFn, None),
@@ -681,7 +692,7 @@
 
     fn lower_foreign_item_ref(&mut self, i: &ForeignItem) -> hir::ForeignItemRef {
         hir::ForeignItemRef {
-            id: hir::ForeignItemId { def_id: self.resolver.local_def_id(i.id) },
+            id: hir::ForeignItemId { def_id: self.local_def_id(i.id) },
             ident: self.lower_ident(i.ident),
             span: self.lower_span(i.span),
         }
@@ -792,24 +803,25 @@
                 ref ty,
                 ..
             }) => {
-                let ty = ty.as_ref().map(|x| {
-                    self.lower_ty(x, ImplTraitContext::Disallowed(ImplTraitPosition::Type))
-                });
                 let mut generics = generics.clone();
                 add_ty_alias_where_clause(&mut generics, where_clauses, false);
-                let generics = self.lower_generics(
+                self.lower_generics(
                     &generics,
+                    i.id,
                     ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
-                );
-                let kind = hir::TraitItemKind::Type(
-                    self.lower_param_bounds(
-                        bounds,
-                        ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
-                    ),
-                    ty,
-                );
-
-                (generics, kind)
+                    |this| {
+                        let ty = ty.as_ref().map(|x| {
+                            this.lower_ty(x, ImplTraitContext::Disallowed(ImplTraitPosition::Type))
+                        });
+                        hir::TraitItemKind::Type(
+                            this.lower_param_bounds(
+                                bounds,
+                                ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
+                            ),
+                            ty,
+                        )
+                    },
+                )
             }
             AssocItemKind::MacCall(..) => panic!("macro item shouldn't exist at this point"),
         };
@@ -836,7 +848,7 @@
             }
             AssocItemKind::MacCall(..) => unimplemented!(),
         };
-        let id = hir::TraitItemId { def_id: self.resolver.local_def_id(i.id) };
+        let id = hir::TraitItemId { def_id: self.local_def_id(i.id) };
         let defaultness = hir::Defaultness::Default { has_value: has_default };
         hir::TraitItemRef {
             id,
@@ -848,7 +860,7 @@
     }
 
     /// Construct `ExprKind::Err` for the given `span`.
-    crate fn expr_err(&mut self, span: Span) -> hir::Expr<'hir> {
+    pub(crate) fn expr_err(&mut self, span: Span) -> hir::Expr<'hir> {
         self.expr(span, hir::ExprKind::Err, AttrVec::new())
     }
 
@@ -879,21 +891,21 @@
             AssocItemKind::TyAlias(box TyAlias { generics, where_clauses, ty, .. }) => {
                 let mut generics = generics.clone();
                 add_ty_alias_where_clause(&mut generics, *where_clauses, false);
-                let generics = self.lower_generics(
+                self.lower_generics(
                     &generics,
+                    i.id,
                     ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
-                );
-                let kind = match ty {
-                    None => {
-                        let ty = self.arena.alloc(self.ty(i.span, hir::TyKind::Err));
-                        hir::ImplItemKind::TyAlias(ty)
-                    }
-                    Some(ty) => {
-                        let ty = self.lower_ty(ty, ImplTraitContext::TypeAliasesOpaqueTy);
-                        hir::ImplItemKind::TyAlias(ty)
-                    }
-                };
-                (generics, kind)
+                    |this| match ty {
+                        None => {
+                            let ty = this.arena.alloc(this.ty(i.span, hir::TyKind::Err));
+                            hir::ImplItemKind::TyAlias(ty)
+                        }
+                        Some(ty) => {
+                            let ty = this.lower_ty(ty, ImplTraitContext::TypeAliasesOpaqueTy);
+                            hir::ImplItemKind::TyAlias(ty)
+                        }
+                    },
+                )
             }
             AssocItemKind::MacCall(..) => panic!("`TyMac` should have been expanded by now"),
         };
@@ -916,7 +928,7 @@
         let has_value = true;
         let (defaultness, _) = self.lower_defaultness(i.kind.defaultness(), has_value);
         hir::ImplItemRef {
-            id: hir::ImplItemId { def_id: self.resolver.local_def_id(i.id) },
+            id: hir::ImplItemId { def_id: self.local_def_id(i.id) },
             ident: self.lower_ident(i.ident),
             span: self.lower_span(i.span),
             defaultness,
@@ -1234,8 +1246,9 @@
         is_async: Option<NodeId>,
     ) -> (&'hir hir::Generics<'hir>, hir::FnSig<'hir>) {
         let header = self.lower_fn_header(sig.header);
-        let (generics, decl) = self.add_implicit_generics(generics, id, |this, idty, idpb| {
-            this.lower_fn_decl(&sig.decl, Some((id, idty, idpb)), kind, is_async)
+        let itctx = ImplTraitContext::Universal;
+        let (generics, decl) = self.lower_generics(generics, id, itctx, |this| {
+            this.lower_fn_decl(&sig.decl, Some(id), kind, is_async)
         });
         (generics, hir::FnSig { header, decl, span: self.lower_span(sig.span) })
     }
@@ -1292,11 +1305,19 @@
         }
     }
 
-    pub(super) fn lower_generics_mut(
+    /// Return the pair of the lowered `generics` as `hir::Generics` and the evaluation of `f` with
+    /// the carried impl trait definitions and bounds.
+    #[instrument(level = "debug", skip(self, f))]
+    fn lower_generics<T>(
         &mut self,
         generics: &Generics,
-        mut itctx: ImplTraitContext<'_, 'hir>,
-    ) -> GenericsCtor<'hir> {
+        parent_node_id: NodeId,
+        itctx: ImplTraitContext,
+        f: impl FnOnce(&mut Self) -> T,
+    ) -> (&'hir hir::Generics<'hir>, T) {
+        debug_assert!(self.impl_trait_defs.is_empty());
+        debug_assert!(self.impl_trait_bounds.is_empty());
+
         // Error if `?Trait` bounds in where clauses don't refer directly to type parameters.
         // Note: we used to clone these bounds directly onto the type parameter (and avoid lowering
         // these into hir when we lower thee where clauses), but this makes it quite difficult to
@@ -1319,7 +1340,7 @@
                         generics
                             .params
                             .iter()
-                            .any(|p| def_id == self.resolver.local_def_id(p.id).to_def_id())
+                            .any(|p| def_id == self.local_def_id(p.id).to_def_id())
                     }
                     // Either the `bounded_ty` is not a plain type parameter, or
                     // it's not found in the generic type parameters list.
@@ -1344,9 +1365,9 @@
             }
         }
 
-        let mut predicates = SmallVec::new();
+        let mut predicates: SmallVec<[hir::WherePredicate<'hir>; 4]> = SmallVec::new();
         predicates.extend(generics.params.iter().filter_map(|param| {
-            let bounds = self.lower_param_bounds(&param.bounds, itctx.reborrow());
+            let bounds = self.lower_param_bounds(&param.bounds, itctx);
             self.lower_generic_bound_predicate(
                 param.ident,
                 param.id,
@@ -1363,22 +1384,35 @@
                 .map(|predicate| self.lower_where_predicate(predicate)),
         );
 
-        GenericsCtor {
-            params: self.lower_generic_params_mut(&generics.params).collect(),
-            predicates,
-            has_where_clause: !generics.where_clause.predicates.is_empty(),
-            where_clause_span: self.lower_span(generics.where_clause.span),
-            span: self.lower_span(generics.span),
-        }
-    }
+        let mut params: SmallVec<[hir::GenericParam<'hir>; 4]> =
+            self.lower_generic_params_mut(&generics.params).collect();
 
-    pub(super) fn lower_generics(
-        &mut self,
-        generics: &Generics,
-        itctx: ImplTraitContext<'_, 'hir>,
-    ) -> &'hir hir::Generics<'hir> {
-        let generics_ctor = self.lower_generics_mut(generics, itctx);
-        generics_ctor.into_generics(self.arena)
+        // Introduce extra lifetimes if late resolution tells us to.
+        let extra_lifetimes = self.resolver.take_extra_lifetime_params(parent_node_id);
+        params.extend(extra_lifetimes.into_iter().filter_map(|(ident, node_id, res)| {
+            self.lifetime_res_to_generic_param(ident, node_id, res)
+        }));
+
+        let has_where_clause_predicates = !generics.where_clause.predicates.is_empty();
+        let where_clause_span = self.lower_span(generics.where_clause.span);
+        let span = self.lower_span(generics.span);
+        let res = f(self);
+
+        let impl_trait_defs = std::mem::take(&mut self.impl_trait_defs);
+        params.extend(impl_trait_defs.into_iter());
+
+        let impl_trait_bounds = std::mem::take(&mut self.impl_trait_bounds);
+        predicates.extend(impl_trait_bounds.into_iter());
+
+        let lowered_generics = self.arena.alloc(hir::Generics {
+            params: self.arena.alloc_from_iter(params),
+            predicates: self.arena.alloc_from_iter(predicates),
+            has_where_clause_predicates,
+            where_clause_span,
+            span,
+        });
+
+        (lowered_generics, res)
     }
 
     pub(super) fn lower_generic_bound_predicate(
@@ -1413,7 +1447,7 @@
         match kind {
             GenericParamKind::Const { .. } => None,
             GenericParamKind::Type { .. } => {
-                let def_id = self.resolver.local_def_id(id).to_def_id();
+                let def_id = self.local_def_id(id).to_def_id();
                 let ty_path = self.arena.alloc(hir::Path {
                     span: param_span,
                     res: Res::Def(DefKind::TyParam, def_id),
@@ -1436,7 +1470,7 @@
                 let res = self.resolver.get_lifetime_res(id).unwrap_or_else(|| {
                     panic!("Missing resolution for lifetime {:?} at {:?}", id, ident.span)
                 });
-                let lt_id = self.resolver.next_node_id();
+                let lt_id = self.next_node_id();
                 let lifetime = self.new_named_lifetime_with_res(lt_id, ident_span, ident, res);
                 Some(hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate {
                     lifetime,
@@ -1494,24 +1528,3 @@
         }
     }
 }
-
-/// Helper struct for delayed construction of Generics.
-pub(super) struct GenericsCtor<'hir> {
-    pub(super) params: SmallVec<[hir::GenericParam<'hir>; 4]>,
-    pub(super) predicates: SmallVec<[hir::WherePredicate<'hir>; 4]>,
-    has_where_clause: bool,
-    where_clause_span: Span,
-    span: Span,
-}
-
-impl<'hir> GenericsCtor<'hir> {
-    pub(super) fn into_generics(self, arena: &'hir Arena<'hir>) -> &'hir hir::Generics<'hir> {
-        arena.alloc(hir::Generics {
-            params: arena.alloc_from_iter(self.params),
-            predicates: arena.alloc_from_iter(self.predicates),
-            has_where_clause: self.has_where_clause,
-            where_clause_span: self.where_clause_span,
-            span: self.span,
-        })
-    }
-}
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index c143266..cab2de0 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -30,7 +30,6 @@
 //! get confused if the spans from leaf AST nodes occur in multiple places
 //! in the HIR, especially for multiple identifiers.
 
-#![feature(crate_visibility_modifier)]
 #![feature(box_patterns)]
 #![feature(let_chains)]
 #![feature(let_else)]
@@ -38,7 +37,9 @@
 #![recursion_limit = "256"]
 #![allow(rustc::potential_query_instability)]
 
-use rustc_ast::tokenstream::{CanSynthesizeMissingTokens, TokenStream};
+#[macro_use]
+extern crate tracing;
+
 use rustc_ast::visit;
 use rustc_ast::{self as ast, *};
 use rustc_ast_pretty::pprust;
@@ -48,25 +49,25 @@
 use rustc_data_structures::sorted_map::SortedMap;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_data_structures::sync::Lrc;
-use rustc_errors::struct_span_err;
+use rustc_errors::{struct_span_err, Applicability};
 use rustc_hir as hir;
-use rustc_hir::def::{DefKind, Namespace, PartialRes, PerNS, Res};
-use rustc_hir::def_id::{DefId, DefPathHash, LocalDefId, CRATE_DEF_ID};
-use rustc_hir::definitions::{DefKey, DefPathData, Definitions};
+use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res};
+use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
+use rustc_hir::definitions::{DefPathData, Definitions};
 use rustc_hir::{ConstArg, GenericArg, ItemLocalId, ParamName, TraitCandidate};
 use rustc_index::vec::{Idx, IndexVec};
+use rustc_middle::ty::{ResolverAstLowering, ResolverOutputs};
 use rustc_query_system::ich::StableHashingContext;
+use rustc_session::cstore::CrateStoreDyn;
 use rustc_session::parse::feature_err;
-use rustc_session::utils::{FlattenNonterminals, NtToTokenstream};
 use rustc_session::Session;
-use rustc_span::hygiene::{ExpnId, MacroKind};
+use rustc_span::hygiene::MacroKind;
 use rustc_span::source_map::DesugaringKind;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{Span, DUMMY_SP};
 
 use smallvec::SmallVec;
 use std::collections::hash_map::Entry;
-use tracing::{debug, trace};
 
 macro_rules! arena_vec {
     ($this:expr; $($x:expr),*) => (
@@ -88,12 +89,10 @@
     /// Used to assign IDs to HIR nodes that do not directly correspond to AST nodes.
     sess: &'a Session,
 
-    resolver: &'a mut dyn ResolverAstLowering,
-
-    /// HACK(Centril): there is a cyclic dependency between the parser and lowering
-    /// if we don't have this function pointer. To avoid that dependency so that
-    /// `rustc_middle` is independent of the parser, we use dynamic dispatch here.
-    nt_to_tokenstream: NtToTokenstream,
+    definitions: &'a mut Definitions,
+    cstore: &'a CrateStoreDyn,
+    resolutions: &'a ResolverOutputs,
+    resolver: &'a mut ResolverAstLowering,
 
     /// Used to allocate HIR nodes.
     arena: &'hir Arena<'hir>,
@@ -129,6 +128,9 @@
     local_id_to_def_id: SortedMap<ItemLocalId, LocalDefId>,
     trait_map: FxHashMap<ItemLocalId, Box<[TraitCandidate]>>,
 
+    impl_trait_defs: Vec<hir::GenericParam<'hir>>,
+    impl_trait_bounds: Vec<hir::WherePredicate<'hir>>,
+
     /// NodeIds that are lowered inside the current HIR owner.
     node_id_to_local_id: FxHashMap<NodeId, hir::ItemLocalId>,
 
@@ -137,46 +139,6 @@
     allow_into_future: Option<Lrc<[Symbol]>>,
 }
 
-/// Resolution for a lifetime appearing in a type.
-#[derive(Copy, Clone, Debug)]
-pub enum LifetimeRes {
-    /// Successfully linked the lifetime to a generic parameter.
-    Param {
-        /// Id of the generic parameter that introduced it.
-        param: LocalDefId,
-        /// Id of the introducing place. That can be:
-        /// - an item's id, for the item's generic parameters;
-        /// - a TraitRef's ref_id, identifying the `for<...>` binder;
-        /// - a BareFn type's id;
-        /// - a Path's id when this path has parenthesized generic args.
-        ///
-        /// This information is used for impl-trait lifetime captures, to know when to or not to
-        /// capture any given lifetime.
-        binder: NodeId,
-    },
-    /// Created a generic parameter for an anonymous lifetime.
-    Fresh {
-        /// Id of the generic parameter that introduced it.
-        param: LocalDefId,
-        /// Id of the introducing place. See `Param`.
-        binder: NodeId,
-    },
-    /// This variant is used for anonymous lifetimes that we did not resolve during
-    /// late resolution.  Shifting the work to the HIR lifetime resolver.
-    Anonymous {
-        /// Id of the introducing place. See `Param`.
-        binder: NodeId,
-        /// Whether this lifetime was spelled or elided.
-        elided: bool,
-    },
-    /// Explicit `'static` lifetime.
-    Static,
-    /// Resolution failure.
-    Error,
-    /// HACK: This is used to recover the NodeId of an elided lifetime.
-    ElidedAnchor { start: NodeId, end: NodeId },
-}
-
 /// When we lower a lifetime, it is inserted in `captures`, and the resolution is modified so
 /// to point to the lifetime parameter impl-trait will generate.
 /// When traversing `for<...>` binders, they are inserted in `binders_to_ignore` so we know *not*
@@ -199,66 +161,93 @@
     binders_to_ignore: FxHashSet<NodeId>,
 }
 
-pub trait ResolverAstLowering {
-    fn def_key(&self, id: DefId) -> DefKey;
+trait ResolverAstLoweringExt {
+    fn legacy_const_generic_args(&self, expr: &Expr) -> Option<Vec<usize>>;
+    fn get_partial_res(&self, id: NodeId) -> Option<PartialRes>;
+    fn get_import_res(&self, id: NodeId) -> PerNS<Option<Res<NodeId>>>;
+    fn get_label_res(&self, id: NodeId) -> Option<NodeId>;
+    fn get_lifetime_res(&self, id: NodeId) -> Option<LifetimeRes>;
+    fn take_extra_lifetime_params(&mut self, id: NodeId) -> Vec<(Ident, NodeId, LifetimeRes)>;
+    fn decl_macro_kind(&self, def_id: LocalDefId) -> MacroKind;
+}
 
-    fn def_span(&self, id: LocalDefId) -> Span;
+impl ResolverAstLoweringExt for ResolverAstLowering {
+    fn legacy_const_generic_args(&self, expr: &Expr) -> Option<Vec<usize>> {
+        if let ExprKind::Path(None, path) = &expr.kind {
+            // Don't perform legacy const generics rewriting if the path already
+            // has generic arguments.
+            if path.segments.last().unwrap().args.is_some() {
+                return None;
+            }
 
-    fn item_generics_num_lifetimes(&self, def: DefId) -> usize;
+            let partial_res = self.partial_res_map.get(&expr.id)?;
+            if partial_res.unresolved_segments() != 0 {
+                return None;
+            }
 
-    fn legacy_const_generic_args(&mut self, expr: &Expr) -> Option<Vec<usize>>;
+            if let Res::Def(DefKind::Fn, def_id) = partial_res.base_res() {
+                // We only support cross-crate argument rewriting. Uses
+                // within the same crate should be updated to use the new
+                // const generics style.
+                if def_id.is_local() {
+                    return None;
+                }
+
+                if let Some(v) = self.legacy_const_generic_args.get(&def_id) {
+                    return v.clone();
+                }
+            }
+        }
+
+        None
+    }
 
     /// Obtains resolution for a `NodeId` with a single resolution.
-    fn get_partial_res(&self, id: NodeId) -> Option<PartialRes>;
+    fn get_partial_res(&self, id: NodeId) -> Option<PartialRes> {
+        self.partial_res_map.get(&id).copied()
+    }
 
     /// Obtains per-namespace resolutions for `use` statement with the given `NodeId`.
-    fn get_import_res(&self, id: NodeId) -> PerNS<Option<Res<NodeId>>>;
+    fn get_import_res(&self, id: NodeId) -> PerNS<Option<Res<NodeId>>> {
+        self.import_res_map.get(&id).copied().unwrap_or_default()
+    }
 
     /// Obtains resolution for a label with the given `NodeId`.
-    fn get_label_res(&self, id: NodeId) -> Option<NodeId>;
+    fn get_label_res(&self, id: NodeId) -> Option<NodeId> {
+        self.label_res_map.get(&id).copied()
+    }
 
     /// Obtains resolution for a lifetime with the given `NodeId`.
-    fn get_lifetime_res(&self, id: NodeId) -> Option<LifetimeRes>;
+    fn get_lifetime_res(&self, id: NodeId) -> Option<LifetimeRes> {
+        self.lifetimes_res_map.get(&id).copied()
+    }
 
     /// Obtain the list of lifetimes parameters to add to an item.
-    fn take_extra_lifetime_params(&mut self, id: NodeId) -> Vec<(Ident, NodeId, LifetimeRes)>;
+    ///
+    /// Extra lifetime parameters should only be added in places that can appear
+    /// as a `binder` in `LifetimeRes`.
+    ///
+    /// The extra lifetimes that appear from the parenthesized `Fn`-trait desugaring
+    /// should appear at the enclosing `PolyTraitRef`.
+    fn take_extra_lifetime_params(&mut self, id: NodeId) -> Vec<(Ident, NodeId, LifetimeRes)> {
+        self.extra_lifetime_params_map.remove(&id).unwrap_or_default()
+    }
 
-    fn create_stable_hashing_context(&self) -> StableHashingContext<'_>;
-
-    fn definitions(&self) -> &Definitions;
-
-    fn next_node_id(&mut self) -> NodeId;
-
-    fn take_trait_map(&mut self, node: NodeId) -> Option<Vec<hir::TraitCandidate>>;
-
-    fn opt_local_def_id(&self, node: NodeId) -> Option<LocalDefId>;
-
-    fn local_def_id(&self, node: NodeId) -> LocalDefId;
-
-    fn def_path_hash(&self, def_id: DefId) -> DefPathHash;
-
-    fn create_def(
-        &mut self,
-        parent: LocalDefId,
-        node_id: ast::NodeId,
-        data: DefPathData,
-        expn_id: ExpnId,
-        span: Span,
-    ) -> LocalDefId;
-
-    fn decl_macro_kind(&self, def_id: LocalDefId) -> MacroKind;
+    fn decl_macro_kind(&self, def_id: LocalDefId) -> MacroKind {
+        self.builtin_macro_kinds.get(&def_id).copied().unwrap_or(MacroKind::Bang)
+    }
 }
 
 /// Context of `impl Trait` in code, which determines whether it is allowed in an HIR subtree,
 /// and if so, what meaning it has.
-#[derive(Debug)]
-enum ImplTraitContext<'b, 'a> {
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+enum ImplTraitContext {
     /// Treat `impl Trait` as shorthand for a new universal generic parameter.
     /// Example: `fn foo(x: impl Debug)`, where `impl Debug` is conceptually
     /// equivalent to a fresh universal parameter like `fn foo<T: Debug>(x: T)`.
     ///
     /// Newly generated parameters should be inserted into the given `Vec`.
-    Universal(&'b mut Vec<hir::GenericParam<'a>>, &'b mut Vec<hir::WherePredicate<'a>>, LocalDefId),
+    Universal,
 
     /// Treat `impl Trait` as shorthand for a new opaque type.
     /// Example: `fn foo() -> impl Debug`, where `impl Debug` is conceptually
@@ -298,18 +287,6 @@
     ImplReturn,
 }
 
-impl<'a> ImplTraitContext<'_, 'a> {
-    fn reborrow<'this>(&'this mut self) -> ImplTraitContext<'this, 'a> {
-        use self::ImplTraitContext::*;
-        match self {
-            Universal(params, bounds, parent) => Universal(params, bounds, *parent),
-            ReturnPositionOpaqueTy { origin } => ReturnPositionOpaqueTy { origin: *origin },
-            TypeAliasesOpaqueTy => TypeAliasesOpaqueTy,
-            Disallowed(pos) => Disallowed(*pos),
-        }
-    }
-}
-
 impl std::fmt::Display for ImplTraitPosition {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         let name = match self {
@@ -368,17 +345,17 @@
 }
 
 fn index_crate<'a>(
-    resolver: &dyn ResolverAstLowering,
+    node_id_to_def_id: &FxHashMap<NodeId, LocalDefId>,
     krate: &'a Crate,
 ) -> IndexVec<LocalDefId, AstOwner<'a>> {
-    let mut indexer = Indexer { resolver, index: IndexVec::new() };
+    let mut indexer = Indexer { node_id_to_def_id, index: IndexVec::new() };
     indexer.index.ensure_contains_elem(CRATE_DEF_ID, || AstOwner::NonOwner);
     indexer.index[CRATE_DEF_ID] = AstOwner::Crate(krate);
     visit::walk_crate(&mut indexer, krate);
     return indexer.index;
 
     struct Indexer<'s, 'a> {
-        resolver: &'s dyn ResolverAstLowering,
+        node_id_to_def_id: &'s FxHashMap<NodeId, LocalDefId>,
         index: IndexVec<LocalDefId, AstOwner<'a>>,
     }
 
@@ -389,21 +366,21 @@
         }
 
         fn visit_item(&mut self, item: &'a ast::Item) {
-            let def_id = self.resolver.local_def_id(item.id);
+            let def_id = self.node_id_to_def_id[&item.id];
             self.index.ensure_contains_elem(def_id, || AstOwner::NonOwner);
             self.index[def_id] = AstOwner::Item(item);
             visit::walk_item(self, item)
         }
 
         fn visit_assoc_item(&mut self, item: &'a ast::AssocItem, ctxt: visit::AssocCtxt) {
-            let def_id = self.resolver.local_def_id(item.id);
+            let def_id = self.node_id_to_def_id[&item.id];
             self.index.ensure_contains_elem(def_id, || AstOwner::NonOwner);
             self.index[def_id] = AstOwner::AssocItem(item, ctxt);
             visit::walk_assoc_item(self, item, ctxt);
         }
 
         fn visit_foreign_item(&mut self, item: &'a ast::ForeignItem) {
-            let def_id = self.resolver.local_def_id(item.id);
+            let def_id = self.node_id_to_def_id[&item.id];
             self.index.ensure_contains_elem(def_id, || AstOwner::NonOwner);
             self.index[def_id] = AstOwner::ForeignItem(item);
             visit::walk_foreign_item(self, item);
@@ -414,44 +391,51 @@
 /// Compute the hash for the HIR of the full crate.
 /// This hash will then be part of the crate_hash which is stored in the metadata.
 fn compute_hir_hash(
-    resolver: &mut dyn ResolverAstLowering,
+    sess: &Session,
+    definitions: &Definitions,
+    cstore: &CrateStoreDyn,
+    resolver: &ResolverOutputs,
     owners: &IndexVec<LocalDefId, hir::MaybeOwner<&hir::OwnerInfo<'_>>>,
 ) -> Fingerprint {
     let mut hir_body_nodes: Vec<_> = owners
         .iter_enumerated()
         .filter_map(|(def_id, info)| {
             let info = info.as_owner()?;
-            let def_path_hash = resolver.definitions().def_path_hash(def_id);
+            let def_path_hash = definitions.def_path_hash(def_id);
             Some((def_path_hash, info))
         })
         .collect();
     hir_body_nodes.sort_unstable_by_key(|bn| bn.0);
 
     let mut stable_hasher = StableHasher::new();
-    let mut hcx = resolver.create_stable_hashing_context();
+    let mut hcx = StableHashingContext::new(sess, definitions, cstore, &resolver.source_span);
     hir_body_nodes.hash_stable(&mut hcx, &mut stable_hasher);
     stable_hasher.finish()
 }
 
-pub fn lower_crate<'a, 'hir>(
-    sess: &'a Session,
-    krate: &'a Crate,
-    resolver: &'a mut dyn ResolverAstLowering,
-    nt_to_tokenstream: NtToTokenstream,
+pub fn lower_crate<'hir>(
+    sess: &Session,
+    krate: &Crate,
+    definitions: &mut Definitions,
+    cstore: &CrateStoreDyn,
+    resolutions: &ResolverOutputs,
+    mut resolver: ResolverAstLowering,
     arena: &'hir Arena<'hir>,
 ) -> &'hir hir::Crate<'hir> {
     let _prof_timer = sess.prof.verbose_generic_activity("hir_lowering");
 
-    let ast_index = index_crate(resolver, krate);
+    let ast_index = index_crate(&resolver.node_id_to_def_id, krate);
 
     let mut owners =
-        IndexVec::from_fn_n(|_| hir::MaybeOwner::Phantom, resolver.definitions().def_index_count());
+        IndexVec::from_fn_n(|_| hir::MaybeOwner::Phantom, definitions.def_index_count());
 
     for def_id in ast_index.indices() {
         item::ItemLowerer {
             sess,
-            resolver,
-            nt_to_tokenstream,
+            definitions,
+            cstore,
+            resolutions,
+            resolver: &mut resolver,
             arena,
             ast_index: &ast_index,
             owners: &mut owners,
@@ -459,12 +443,12 @@
         .lower_node(def_id);
     }
 
-    let hir_hash = compute_hir_hash(resolver, &owners);
+    let hir_hash = compute_hir_hash(sess, definitions, cstore, resolutions, &owners);
     let krate = hir::Crate { owners, hir_hash };
     arena.alloc(krate)
 }
 
-#[derive(Copy, Clone, PartialEq)]
+#[derive(Copy, Clone, PartialEq, Debug)]
 enum ParamMode {
     /// Any path in a type context.
     Explicit,
@@ -480,12 +464,64 @@
 }
 
 impl<'a, 'hir> LoweringContext<'a, 'hir> {
+    fn create_stable_hashing_context(&self) -> StableHashingContext<'_> {
+        StableHashingContext::new(
+            self.sess,
+            self.definitions,
+            self.cstore,
+            &self.resolutions.source_span,
+        )
+    }
+
+    fn create_def(
+        &mut self,
+        parent: LocalDefId,
+        node_id: ast::NodeId,
+        data: DefPathData,
+    ) -> LocalDefId {
+        assert!(
+            self.opt_local_def_id(node_id).is_none(),
+            "adding a def'n for node-id {:?} and data {:?} but a previous def'n exists: {:?}",
+            node_id,
+            data,
+            self.definitions.def_key(self.local_def_id(node_id)),
+        );
+
+        let def_id = self.definitions.create_def(parent, data);
+
+        // Some things for which we allocate `LocalDefId`s don't correspond to
+        // anything in the AST, so they don't have a `NodeId`. For these cases
+        // we don't need a mapping from `NodeId` to `LocalDefId`.
+        if node_id != ast::DUMMY_NODE_ID {
+            debug!("create_def: def_id_to_node_id[{:?}] <-> {:?}", def_id, node_id);
+            self.resolver.node_id_to_def_id.insert(node_id, def_id);
+        }
+
+        def_id
+    }
+
+    fn next_node_id(&mut self) -> NodeId {
+        let start = self.resolver.next_node_id;
+        let next = start.as_u32().checked_add(1).expect("input too large; ran out of NodeIds");
+        self.resolver.next_node_id = ast::NodeId::from_u32(next);
+        start
+    }
+
+    fn opt_local_def_id(&self, node: NodeId) -> Option<LocalDefId> {
+        self.resolver.node_id_to_def_id.get(&node).copied()
+    }
+
+    fn local_def_id(&self, node: NodeId) -> LocalDefId {
+        self.opt_local_def_id(node).unwrap_or_else(|| panic!("no entry for node id: `{:?}`", node))
+    }
+
+    #[instrument(level = "debug", skip(self, f))]
     fn with_hir_id_owner(
         &mut self,
         owner: NodeId,
         f: impl FnOnce(&mut Self) -> hir::OwnerNode<'hir>,
     ) {
-        let def_id = self.resolver.local_def_id(owner);
+        let def_id = self.local_def_id(owner);
 
         let current_attrs = std::mem::take(&mut self.attrs);
         let current_bodies = std::mem::take(&mut self.bodies);
@@ -495,6 +531,10 @@
         let current_owner = std::mem::replace(&mut self.current_hir_id_owner, def_id);
         let current_local_counter =
             std::mem::replace(&mut self.item_local_id_counter, hir::ItemLocalId::new(1));
+        let current_impl_trait_defs = std::mem::take(&mut self.impl_trait_defs);
+        let current_impl_trait_bounds = std::mem::take(&mut self.impl_trait_bounds);
+        // Do not reset `next_node_id` and `node_id_to_def_id` as we want to refer to the
+        // subdefinitions' nodes.
 
         // Always allocate the first `HirId` for the owner itself.
         let _old = self.node_id_to_local_id.insert(owner, hir::ItemLocalId::new(0));
@@ -502,6 +542,9 @@
 
         let item = f(self);
         debug_assert_eq!(def_id, item.def_id());
+        // `f` should have consumed all the elements in these vectors when constructing `item`.
+        debug_assert!(self.impl_trait_defs.is_empty());
+        debug_assert!(self.impl_trait_bounds.is_empty());
         let info = self.make_owner_info(item);
 
         self.attrs = current_attrs;
@@ -511,6 +554,8 @@
         self.trait_map = current_trait_map;
         self.current_hir_id_owner = current_owner;
         self.item_local_id_counter = current_local_counter;
+        self.impl_trait_defs = current_impl_trait_defs;
+        self.impl_trait_bounds = current_impl_trait_bounds;
 
         let _old = self.children.insert(def_id, hir::MaybeOwner::Owner(info));
         debug_assert!(_old.is_none())
@@ -533,8 +578,7 @@
         bodies.sort_by_key(|(k, _)| *k);
         let bodies = SortedMap::from_presorted_elements(bodies);
         let (hash_including_bodies, hash_without_bodies) = self.hash_owner(node, &bodies);
-        let (nodes, parenting) =
-            index::index_hir(self.sess, self.resolver.definitions(), node, &bodies);
+        let (nodes, parenting) = index::index_hir(self.sess, self.definitions, node, &bodies);
         let nodes = hir::OwnerNodes {
             hash_including_bodies,
             hash_without_bodies,
@@ -543,7 +587,7 @@
             local_id_to_def_id,
         };
         let attrs = {
-            let mut hcx = self.resolver.create_stable_hashing_context();
+            let mut hcx = self.create_stable_hashing_context();
             let mut stable_hasher = StableHasher::new();
             attrs.hash_stable(&mut hcx, &mut stable_hasher);
             let hash = stable_hasher.finish();
@@ -560,7 +604,7 @@
         node: hir::OwnerNode<'hir>,
         bodies: &SortedMap<hir::ItemLocalId, &'hir hir::Body<'hir>>,
     ) -> (Fingerprint, Fingerprint) {
-        let mut hcx = self.resolver.create_stable_hashing_context();
+        let mut hcx = self.create_stable_hashing_context();
         let mut stable_hasher = StableHasher::new();
         hcx.with_hir_bodies(true, node.def_id(), bodies, |hcx| {
             node.hash_stable(hcx, &mut stable_hasher)
@@ -597,13 +641,13 @@
                 self.item_local_id_counter.increment_by(1);
 
                 assert_ne!(local_id, hir::ItemLocalId::new(0));
-                if let Some(def_id) = self.resolver.opt_local_def_id(ast_node_id) {
+                if let Some(def_id) = self.opt_local_def_id(ast_node_id) {
                     // Do not override a `MaybeOwner::Owner` that may already here.
                     self.children.entry(def_id).or_insert(hir::MaybeOwner::NonOwner(hir_id));
                     self.local_id_to_def_id.insert(local_id, def_id);
                 }
 
-                if let Some(traits) = self.resolver.take_trait_map(ast_node_id) {
+                if let Some(traits) = self.resolver.trait_map.remove(&ast_node_id) {
                     self.trait_map.insert(hir_id.local_id, traits.into_boxed_slice());
                 }
 
@@ -613,16 +657,19 @@
     }
 
     fn next_id(&mut self) -> hir::HirId {
-        let node_id = self.resolver.next_node_id();
+        let node_id = self.next_node_id();
         self.lower_node_id(node_id)
     }
 
+    #[instrument(level = "trace", skip(self))]
     fn lower_res(&mut self, res: Res<NodeId>) -> Res {
         let res: Result<Res, ()> = res.apply_id(|id| {
             let owner = self.current_hir_id_owner;
             let local_id = self.node_id_to_local_id.get(&id).copied().ok_or(())?;
             Ok(hir::HirId { owner, local_id })
         });
+        trace!(?res);
+
         // We may fail to find a HirId when the Res points to a Local from an enclosing HIR owner.
         // This can happen when trying to lower the return type `x` in erroneous code like
         //   async fn foo(x: u8) -> x {}
@@ -660,7 +707,7 @@
             allow_internal_unstable,
             reason,
             self.sess.edition(),
-            self.resolver.create_stable_hashing_context(),
+            self.create_stable_hashing_context(),
         )
     }
 
@@ -680,6 +727,7 @@
     }
 
     /// Converts a lifetime into a new generic parameter.
+    #[tracing::instrument(level = "debug", skip(self))]
     fn lifetime_res_to_generic_param(
         &mut self,
         ident: Ident,
@@ -691,7 +739,15 @@
                 (hir::ParamName::Plain(ident), hir::LifetimeParamKind::Explicit)
             }
             LifetimeRes::Fresh { param, .. } => {
-                (hir::ParamName::Fresh(param), hir::LifetimeParamKind::Elided)
+                // Late resolution delegates to us the creation of the `LocalDefId`.
+                let _def_id = self.create_def(
+                    self.current_hir_id_owner,
+                    param,
+                    DefPathData::LifetimeNs(kw::UnderscoreLifetime),
+                );
+                debug!(?_def_id);
+
+                (hir::ParamName::Fresh, hir::LifetimeParamKind::Elided)
             }
             LifetimeRes::Static | LifetimeRes::Error => return None,
             res => panic!(
@@ -710,46 +766,6 @@
         })
     }
 
-    /// Creates a new `hir::GenericParam` for every new `Fresh` lifetime and
-    /// universal `impl Trait` type parameter encountered while evaluating `f`.
-    /// Definitions are created with the provided `parent_def_id`.
-    fn add_implicit_generics<T>(
-        &mut self,
-        generics: &Generics,
-        parent_node_id: NodeId,
-        f: impl FnOnce(
-            &mut Self,
-            &mut Vec<hir::GenericParam<'hir>>,
-            &mut Vec<hir::WherePredicate<'hir>>,
-        ) -> T,
-    ) -> (&'hir hir::Generics<'hir>, T) {
-        let mut impl_trait_defs = Vec::new();
-        let mut impl_trait_bounds = Vec::new();
-        let mut lowered_generics = self.lower_generics_mut(
-            generics,
-            ImplTraitContext::Universal(
-                &mut impl_trait_defs,
-                &mut impl_trait_bounds,
-                self.current_hir_id_owner,
-            ),
-        );
-        let res = f(self, &mut impl_trait_defs, &mut impl_trait_bounds);
-
-        let extra_lifetimes = self.resolver.take_extra_lifetime_params(parent_node_id);
-        lowered_generics.params.extend(
-            extra_lifetimes
-                .into_iter()
-                .filter_map(|(ident, node_id, res)| {
-                    self.lifetime_res_to_generic_param(ident, node_id, res)
-                })
-                .chain(impl_trait_defs),
-        );
-        lowered_generics.predicates.extend(impl_trait_bounds);
-
-        let lowered_generics = lowered_generics.into_generics(self.arena);
-        (lowered_generics, res)
-    }
-
     /// Setup lifetime capture for and impl-trait.
     /// The captures will be added to `captures`.
     fn while_capturing_lifetimes<T>(
@@ -778,11 +794,25 @@
     /// Register a binder to be ignored for lifetime capture.
     #[tracing::instrument(level = "debug", skip(self, f))]
     #[inline]
-    fn with_lifetime_binder<T>(&mut self, binder: NodeId, f: impl FnOnce(&mut Self) -> T) -> T {
+    fn with_lifetime_binder<T>(
+        &mut self,
+        binder: NodeId,
+        generic_params: &[GenericParam],
+        f: impl FnOnce(&mut Self, &'hir [hir::GenericParam<'hir>]) -> T,
+    ) -> T {
+        let mut generic_params: Vec<_> = self.lower_generic_params_mut(generic_params).collect();
+        let extra_lifetimes = self.resolver.take_extra_lifetime_params(binder);
+        debug!(?extra_lifetimes);
+        generic_params.extend(extra_lifetimes.into_iter().filter_map(|(ident, node_id, res)| {
+            self.lifetime_res_to_generic_param(ident, node_id, res)
+        }));
+        let generic_params = self.arena.alloc_from_iter(generic_params);
+        debug!(?generic_params);
+
         if let Some(ctxt) = &mut self.captured_lifetimes {
             ctxt.binders_to_ignore.insert(binder);
         }
-        let ret = f(self);
+        let ret = f(self, generic_params);
         if let Some(ctxt) = &mut self.captured_lifetimes {
             ctxt.binders_to_ignore.remove(&binder);
         }
@@ -876,11 +906,7 @@
                 // ```
                 //
                 // In both cases, we don't want to synthesize any tokens
-                MacArgs::Delimited(
-                    dspan,
-                    delim,
-                    self.lower_token_stream(tokens.clone(), CanSynthesizeMissingTokens::No),
-                )
+                MacArgs::Delimited(dspan, delim, tokens.flattened())
             }
             // This is an inert key-value attribute - it will never be visible to macros
             // after it gets lowered to HIR. Therefore, we can extract literals to handle
@@ -905,19 +931,6 @@
         }
     }
 
-    fn lower_token_stream(
-        &self,
-        tokens: TokenStream,
-        synthesize_tokens: CanSynthesizeMissingTokens,
-    ) -> TokenStream {
-        FlattenNonterminals {
-            parse_sess: &self.sess.parse_sess,
-            synthesize_tokens,
-            nt_to_tokenstream: self.nt_to_tokenstream,
-        }
-        .process_token_stream(tokens)
-    }
-
     /// Given an associated type constraint like one of these:
     ///
     /// ```ignore (illustrative)
@@ -928,35 +941,25 @@
     /// ```
     ///
     /// returns a `hir::TypeBinding` representing `Item`.
+    #[instrument(level = "debug", skip(self))]
     fn lower_assoc_ty_constraint(
         &mut self,
         constraint: &AssocConstraint,
-        mut itctx: ImplTraitContext<'_, 'hir>,
+        itctx: ImplTraitContext,
     ) -> hir::TypeBinding<'hir> {
         debug!("lower_assoc_ty_constraint(constraint={:?}, itctx={:?})", constraint, itctx);
-
         // lower generic arguments of identifier in constraint
         let gen_args = if let Some(ref gen_args) = constraint.gen_args {
             let gen_args_ctor = match gen_args {
                 GenericArgs::AngleBracketed(ref data) => {
-                    self.lower_angle_bracketed_parameter_data(
-                        data,
-                        ParamMode::Explicit,
-                        itctx.reborrow(),
-                    )
-                    .0
+                    self.lower_angle_bracketed_parameter_data(data, ParamMode::Explicit, itctx).0
                 }
                 GenericArgs::Parenthesized(ref data) => {
-                    let mut err = self.sess.struct_span_err(
-                        gen_args.span(),
-                        "parenthesized generic arguments cannot be used in associated type constraints"
-                    );
-                    // FIXME: try to write a suggestion here
-                    err.emit();
+                    self.emit_bad_parenthesized_trait_in_assoc_ty(data);
                     self.lower_angle_bracketed_parameter_data(
                         &data.as_angle_bracketed_args(),
                         ParamMode::Explicit,
-                        itctx.reborrow(),
+                        itctx,
                     )
                     .0
                 }
@@ -975,7 +978,6 @@
                 hir::TypeBindingKind::Equality { term }
             }
             AssocConstraintKind::Bound { ref bounds } => {
-                let mut parent_def_id = self.current_hir_id_owner;
                 // Piggy-back on the `impl Trait` context to figure out the correct behavior.
                 let (desugar_to_impl_trait, itctx) = match itctx {
                     // We are in the return position:
@@ -995,10 +997,7 @@
                     // so desugar to
                     //
                     //     fn foo(x: dyn Iterator<Item = impl Debug>)
-                    ImplTraitContext::Universal(_, _, parent) if self.is_in_dyn_type => {
-                        parent_def_id = parent;
-                        (true, itctx)
-                    }
+                    ImplTraitContext::Universal if self.is_in_dyn_type => (true, itctx),
 
                     // In `type Foo = dyn Iterator<Item: Debug>` we desugar to
                     // `type Foo = dyn Iterator<Item = impl Debug>` but we have to override the
@@ -1024,17 +1023,12 @@
                     // Desugar `AssocTy: Bounds` into `AssocTy = impl Bounds`. We do this by
                     // constructing the HIR for `impl bounds...` and then lowering that.
 
-                    let impl_trait_node_id = self.resolver.next_node_id();
-                    self.resolver.create_def(
-                        parent_def_id,
-                        impl_trait_node_id,
-                        DefPathData::ImplTrait,
-                        ExpnId::root(),
-                        constraint.span,
-                    );
+                    let parent_def_id = self.current_hir_id_owner;
+                    let impl_trait_node_id = self.next_node_id();
+                    self.create_def(parent_def_id, impl_trait_node_id, DefPathData::ImplTrait);
 
                     self.with_dyn_type_scope(false, |this| {
-                        let node_id = this.resolver.next_node_id();
+                        let node_id = this.next_node_id();
                         let ty = this.lower_ty(
                             &Ty {
                                 id: node_id,
@@ -1066,10 +1060,47 @@
         }
     }
 
+    fn emit_bad_parenthesized_trait_in_assoc_ty(&self, data: &ParenthesizedArgs) {
+        let mut err = self.sess.struct_span_err(
+            data.span,
+            "parenthesized generic arguments cannot be used in associated type constraints",
+        );
+        // Suggest removing empty parentheses: "Trait()" -> "Trait"
+        if data.inputs.is_empty() {
+            let parentheses_span =
+                data.inputs_span.shrink_to_lo().to(data.inputs_span.shrink_to_hi());
+            err.multipart_suggestion(
+                "remove these parentheses",
+                vec![(parentheses_span, String::new())],
+                Applicability::MaybeIncorrect,
+            );
+        }
+        // Suggest replacing parentheses with angle brackets `Trait(params...)` to `Trait<params...>`
+        else {
+            // Start of parameters to the 1st argument
+            let open_param = data.inputs_span.shrink_to_lo().to(data
+                .inputs
+                .first()
+                .unwrap()
+                .span
+                .shrink_to_lo());
+            // End of last argument to end of parameters
+            let close_param =
+                data.inputs.last().unwrap().span.shrink_to_hi().to(data.inputs_span.shrink_to_hi());
+            err.multipart_suggestion(
+                &format!("use angle brackets instead",),
+                vec![(open_param, String::from("<")), (close_param, String::from(">"))],
+                Applicability::MaybeIncorrect,
+            );
+        }
+        err.emit();
+    }
+
+    #[instrument(level = "debug", skip(self))]
     fn lower_generic_arg(
         &mut self,
         arg: &ast::GenericArg,
-        itctx: ImplTraitContext<'_, 'hir>,
+        itctx: ImplTraitContext,
     ) -> hir::GenericArg<'hir> {
         match arg {
             ast::GenericArg::Lifetime(lt) => GenericArg::Lifetime(self.lower_lifetime(&lt)),
@@ -1097,16 +1128,10 @@
                                 // Construct an AnonConst where the expr is the "ty"'s path.
 
                                 let parent_def_id = self.current_hir_id_owner;
-                                let node_id = self.resolver.next_node_id();
+                                let node_id = self.next_node_id();
 
                                 // Add a definition for the in-band const def.
-                                self.resolver.create_def(
-                                    parent_def_id,
-                                    node_id,
-                                    DefPathData::AnonConst,
-                                    ExpnId::root(),
-                                    ty.span,
-                                );
+                                self.create_def(parent_def_id, node_id, DefPathData::AnonConst);
 
                                 let span = self.lower_span(ty.span);
                                 let path_expr = Expr {
@@ -1136,7 +1161,8 @@
         }
     }
 
-    fn lower_ty(&mut self, t: &Ty, itctx: ImplTraitContext<'_, 'hir>) -> &'hir hir::Ty<'hir> {
+    #[instrument(level = "debug", skip(self))]
+    fn lower_ty(&mut self, t: &Ty, itctx: ImplTraitContext) -> &'hir hir::Ty<'hir> {
         self.arena.alloc(self.lower_ty_direct(t, itctx))
     }
 
@@ -1146,8 +1172,35 @@
         qself: &Option<QSelf>,
         path: &Path,
         param_mode: ParamMode,
-        itctx: ImplTraitContext<'_, 'hir>,
+        itctx: ImplTraitContext,
     ) -> hir::Ty<'hir> {
+        // Check whether we should interpret this as a bare trait object.
+        // This check mirrors the one in late resolution.  We only introduce this special case in
+        // the rare occurence we need to lower `Fresh` anonymous lifetimes.
+        // The other cases when a qpath should be opportunistically made a trait object are handled
+        // by `ty_path`.
+        if qself.is_none()
+            && let Some(partial_res) = self.resolver.get_partial_res(t.id)
+            && partial_res.unresolved_segments() == 0
+            && let Res::Def(DefKind::Trait | DefKind::TraitAlias, _) = partial_res.base_res()
+        {
+            let (bounds, lifetime_bound) = self.with_dyn_type_scope(true, |this| {
+                let bound = this.lower_poly_trait_ref(
+                    &PolyTraitRef {
+                        bound_generic_params: vec![],
+                        trait_ref: TraitRef { path: path.clone(), ref_id: t.id },
+                        span: t.span
+                    },
+                    itctx,
+                );
+                let bounds = this.arena.alloc_from_iter([bound]);
+                let lifetime_bound = this.elided_dyn_bound(t.span);
+                (bounds, lifetime_bound)
+            });
+            let kind = hir::TyKind::TraitObject(bounds, lifetime_bound, TraitObjectSyntax::None);
+            return hir::Ty { kind, span: self.lower_span(t.span), hir_id: self.next_id() };
+        }
+
         let id = self.lower_node_id(t.id);
         let qpath = self.lower_qpath(t.id, qself, path, param_mode, itctx);
         self.ty_path(id, t.span, qpath)
@@ -1161,7 +1214,7 @@
         self.ty(span, hir::TyKind::Tup(tys))
     }
 
-    fn lower_ty_direct(&mut self, t: &Ty, mut itctx: ImplTraitContext<'_, 'hir>) -> hir::Ty<'hir> {
+    fn lower_ty_direct(&mut self, t: &Ty, itctx: ImplTraitContext) -> hir::Ty<'hir> {
         let kind = match t.kind {
             TyKind::Infer => hir::TyKind::Infer,
             TyKind::Err => hir::TyKind::Err,
@@ -1169,34 +1222,35 @@
             TyKind::Ptr(ref mt) => hir::TyKind::Ptr(self.lower_mt(mt, itctx)),
             TyKind::Rptr(ref region, ref mt) => {
                 let region = region.unwrap_or_else(|| {
-                    let Some(LifetimeRes::ElidedAnchor { start, end }) = self.resolver.get_lifetime_res(t.id) else {
-                        panic!()
+                    let id = if let Some(LifetimeRes::ElidedAnchor { start, end }) =
+                        self.resolver.get_lifetime_res(t.id)
+                    {
+                        debug_assert_eq!(start.plus(1), end);
+                        start
+                    } else {
+                        self.next_node_id()
                     };
-                    debug_assert_eq!(start.plus(1), end);
                     let span = self.sess.source_map().next_point(t.span.shrink_to_lo());
-                    Lifetime {
-                        ident: Ident::new(kw::UnderscoreLifetime, span),
-                        id: start,
-                    }
+                    Lifetime { ident: Ident::new(kw::UnderscoreLifetime, span), id }
                 });
                 let lifetime = self.lower_lifetime(&region);
                 hir::TyKind::Rptr(lifetime, self.lower_mt(mt, itctx))
             }
-            TyKind::BareFn(ref f) => self.with_lifetime_binder(t.id, |this| {
-                hir::TyKind::BareFn(this.arena.alloc(hir::BareFnTy {
-                    generic_params: this.lower_generic_params(&f.generic_params),
-                    unsafety: this.lower_unsafety(f.unsafety),
-                    abi: this.lower_extern(f.ext),
-                    decl: this.lower_fn_decl(&f.decl, None, FnDeclKind::Pointer, None),
-                    param_names: this.lower_fn_params_to_names(&f.decl),
-                }))
-            }),
-            TyKind::Never => hir::TyKind::Never,
-            TyKind::Tup(ref tys) => {
-                hir::TyKind::Tup(self.arena.alloc_from_iter(
-                    tys.iter().map(|ty| self.lower_ty_direct(ty, itctx.reborrow())),
-                ))
+            TyKind::BareFn(ref f) => {
+                self.with_lifetime_binder(t.id, &f.generic_params, |this, generic_params| {
+                    hir::TyKind::BareFn(this.arena.alloc(hir::BareFnTy {
+                        generic_params,
+                        unsafety: this.lower_unsafety(f.unsafety),
+                        abi: this.lower_extern(f.ext),
+                        decl: this.lower_fn_decl(&f.decl, None, FnDeclKind::Pointer, None),
+                        param_names: this.lower_fn_params_to_names(&f.decl),
+                    }))
+                })
             }
+            TyKind::Never => hir::TyKind::Never,
+            TyKind::Tup(ref tys) => hir::TyKind::Tup(
+                self.arena.alloc_from_iter(tys.iter().map(|ty| self.lower_ty_direct(ty, itctx))),
+            ),
             TyKind::Paren(ref ty) => {
                 return self.lower_ty_direct(ty, itctx);
             }
@@ -1230,7 +1284,7 @@
                                 GenericBound::Trait(
                                     ref ty,
                                     TraitBoundModifier::None | TraitBoundModifier::MaybeConst,
-                                ) => Some(this.lower_poly_trait_ref(ty, itctx.reborrow())),
+                                ) => Some(this.lower_poly_trait_ref(ty, itctx)),
                                 // `~const ?Bound` will cause an error during AST validation
                                 // anyways, so treat it like `?Bound` as compilation proceeds.
                                 GenericBound::Trait(
@@ -1267,50 +1321,16 @@
                             |this| this.lower_param_bounds(bounds, nested_itctx),
                         )
                     }
-                    ImplTraitContext::Universal(
-                        in_band_ty_params,
-                        in_band_ty_bounds,
-                        parent_def_id,
-                    ) => {
-                        // Add a definition for the in-band `Param`.
-                        let def_id = self.resolver.local_def_id(def_node_id);
-
-                        let hir_bounds = self.lower_param_bounds(
-                            bounds,
-                            ImplTraitContext::Universal(
-                                in_band_ty_params,
-                                in_band_ty_bounds,
-                                parent_def_id,
-                            ),
-                        );
-                        // Set the name to `impl Bound1 + Bound2`.
+                    ImplTraitContext::Universal => {
+                        let span = t.span;
                         let ident = Ident::from_str_and_span(&pprust::ty_to_string(t), span);
-                        in_band_ty_params.push(hir::GenericParam {
-                            hir_id: self.lower_node_id(def_node_id),
-                            name: ParamName::Plain(self.lower_ident(ident)),
-                            pure_wrt_drop: false,
-                            span: self.lower_span(span),
-                            kind: hir::GenericParamKind::Type { default: None, synthetic: true },
-                            colon_span: None,
-                        });
-                        if let Some(preds) = self.lower_generic_bound_predicate(
-                            ident,
-                            def_node_id,
-                            &GenericParamKind::Type { default: None },
-                            hir_bounds,
-                            hir::PredicateOrigin::ImplTrait,
-                        ) {
-                            in_band_ty_bounds.push(preds)
+                        let (param, bounds, path) =
+                            self.lower_generic_and_bounds(def_node_id, span, ident, bounds);
+                        self.impl_trait_defs.push(param);
+                        if let Some(bounds) = bounds {
+                            self.impl_trait_bounds.push(bounds);
                         }
-
-                        hir::TyKind::Path(hir::QPath::Resolved(
-                            None,
-                            self.arena.alloc(hir::Path {
-                                span: self.lower_span(span),
-                                res: Res::Def(DefKind::TyParam, def_id.to_def_id()),
-                                segments: arena_vec![self; hir::PathSegment::from_ident(self.lower_ident(ident))],
-                            }),
-                        ))
+                        path
                     }
                     ImplTraitContext::Disallowed(position) => {
                         let mut err = struct_span_err!(
@@ -1353,7 +1373,7 @@
         // frequently opened issues show.
         let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::OpaqueTy, span, None);
 
-        let opaque_ty_def_id = self.resolver.local_def_id(opaque_ty_node_id);
+        let opaque_ty_def_id = self.local_def_id(opaque_ty_node_id);
 
         let mut collected_lifetimes = FxHashMap::default();
         self.with_hir_id_owner(opaque_ty_node_id, |lctx| {
@@ -1371,7 +1391,7 @@
             let lifetime_defs = lctx.arena.alloc_from_iter(collected_lifetimes.iter().map(
                 |(_, &(span, p_id, p_name, _))| {
                     let hir_id = lctx.lower_node_id(p_id);
-                    debug_assert_ne!(lctx.resolver.opt_local_def_id(p_id), None);
+                    debug_assert_ne!(lctx.opt_local_def_id(p_id), None);
 
                     let kind = if p_name.ident().name == kw::UnderscoreLifetime {
                         hir::LifetimeParamKind::Elided
@@ -1396,7 +1416,7 @@
                 generics: self.arena.alloc(hir::Generics {
                     params: lifetime_defs,
                     predicates: &[],
-                    has_where_clause: false,
+                    has_where_clause_predicates: false,
                     where_clause_span: lctx.lower_span(span),
                     span: lctx.lower_span(span),
                 }),
@@ -1410,7 +1430,7 @@
 
         let lifetimes = self.arena.alloc_from_iter(collected_lifetimes.into_iter().map(
             |(_, (span, _, p_name, res))| {
-                let id = self.resolver.next_node_id();
+                let id = self.next_node_id();
                 let ident = Ident::new(p_name.ident().name, span);
                 let l = self.new_named_lifetime_with_res(id, span, ident, res);
                 hir::GenericArg::Lifetime(l)
@@ -1471,26 +1491,14 @@
     // `make_ret_async`: if `Some`, converts `-> T` into `-> impl Future<Output = T>` in the
     //      return type. This is used for `async fn` declarations. The `NodeId` is the ID of the
     //      return type `impl Trait` item.
+    #[tracing::instrument(level = "debug", skip(self))]
     fn lower_fn_decl(
         &mut self,
         decl: &FnDecl,
-        mut in_band_ty_params: Option<(
-            NodeId,
-            &mut Vec<hir::GenericParam<'hir>>,
-            &mut Vec<hir::WherePredicate<'hir>>,
-        )>,
+        fn_node_id: Option<NodeId>,
         kind: FnDeclKind,
         make_ret_async: Option<NodeId>,
     ) -> &'hir hir::FnDecl<'hir> {
-        debug!(
-            "lower_fn_decl(\
-            fn_decl: {:?}, \
-            in_band_ty_params: {:?}, \
-            kind: {:?}, \
-            make_ret_async: {:?})",
-            decl, in_band_ty_params, kind, make_ret_async,
-        );
-
         let c_variadic = decl.c_variadic();
 
         // Skip the `...` (`CVarArgs`) trailing arguments from the AST,
@@ -1501,11 +1509,8 @@
             inputs = &inputs[..inputs.len() - 1];
         }
         let inputs = self.arena.alloc_from_iter(inputs.iter().map(|param| {
-            if let Some((_, ibty, ibpb)) = &mut in_band_ty_params {
-                self.lower_ty_direct(
-                    &param.ty,
-                    ImplTraitContext::Universal(ibty, ibpb, self.current_hir_id_owner),
-                )
+            if fn_node_id.is_some() {
+                self.lower_ty_direct(&param.ty, ImplTraitContext::Universal)
             } else {
                 self.lower_ty_direct(
                     &param.ty,
@@ -1526,15 +1531,15 @@
         let output = if let Some(ret_id) = make_ret_async {
             self.lower_async_fn_ret_ty(
                 &decl.output,
-                in_band_ty_params.expect("`make_ret_async` but no `fn_def_id`").0,
+                fn_node_id.expect("`make_ret_async` but no `fn_def_id`"),
                 ret_id,
             )
         } else {
             match decl.output {
                 FnRetTy::Ty(ref ty) => {
-                    let context = match in_band_ty_params {
-                        Some((node_id, _, _)) if kind.impl_trait_return_allowed() => {
-                            let fn_def_id = self.resolver.local_def_id(node_id);
+                    let context = match fn_node_id {
+                        Some(fn_node_id) if kind.impl_trait_return_allowed() => {
+                            let fn_def_id = self.local_def_id(fn_node_id);
                             ImplTraitContext::ReturnPositionOpaqueTy {
                                 origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id),
                             }
@@ -1608,8 +1613,8 @@
 
         let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::Async, span, None);
 
-        let opaque_ty_def_id = self.resolver.local_def_id(opaque_ty_node_id);
-        let fn_def_id = self.resolver.local_def_id(fn_node_id);
+        let opaque_ty_def_id = self.local_def_id(opaque_ty_node_id);
+        let fn_def_id = self.local_def_id(fn_node_id);
 
         // When we create the opaque type for this async fn, it is going to have
         // to capture all the lifetimes involved in the signature (including in the
@@ -1659,17 +1664,11 @@
         debug!(?extra_lifetime_params);
         for (ident, outer_node_id, outer_res) in extra_lifetime_params {
             let Ident { name, span } = ident;
-            let outer_def_id = self.resolver.local_def_id(outer_node_id);
-            let inner_node_id = self.resolver.next_node_id();
+            let outer_def_id = self.local_def_id(outer_node_id);
+            let inner_node_id = self.next_node_id();
 
             // Add a definition for the in scope lifetime def.
-            self.resolver.create_def(
-                opaque_ty_def_id,
-                inner_node_id,
-                DefPathData::LifetimeNs(name),
-                ExpnId::root(),
-                span.with_parent(None),
-            );
+            self.create_def(opaque_ty_def_id, inner_node_id, DefPathData::LifetimeNs(name));
 
             let (p_name, inner_res) = match outer_res {
                 // Input lifetime like `'a`:
@@ -1677,10 +1676,9 @@
                     (hir::ParamName::Plain(ident), LifetimeRes::Param { param, binder: fn_node_id })
                 }
                 // Input lifetime like `'1`:
-                LifetimeRes::Fresh { param, .. } => (
-                    hir::ParamName::Fresh(outer_def_id),
-                    LifetimeRes::Fresh { param, binder: fn_node_id },
-                ),
+                LifetimeRes::Fresh { param, .. } => {
+                    (hir::ParamName::Fresh, LifetimeRes::Fresh { param, binder: fn_node_id })
+                }
                 LifetimeRes::Static | LifetimeRes::Error => continue,
                 res => {
                     panic!("Unexpected lifetime resolution {:?} for {:?} at {:?}", res, ident, span)
@@ -1711,7 +1709,7 @@
             let generic_params =
                 this.arena.alloc_from_iter(captures.iter().map(|(_, &(span, p_id, p_name, _))| {
                     let hir_id = this.lower_node_id(p_id);
-                    debug_assert_ne!(this.resolver.opt_local_def_id(p_id), None);
+                    debug_assert_ne!(this.opt_local_def_id(p_id), None);
 
                     let kind = if p_name.ident().name == kw::UnderscoreLifetime {
                         hir::LifetimeParamKind::Elided
@@ -1734,7 +1732,7 @@
                 generics: this.arena.alloc(hir::Generics {
                     params: generic_params,
                     predicates: &[],
-                    has_where_clause: false,
+                    has_where_clause_predicates: false,
                     where_clause_span: this.lower_span(span),
                     span: this.lower_span(span),
                 }),
@@ -1763,7 +1761,7 @@
         // generate `'_`.
         let generic_args =
             self.arena.alloc_from_iter(captures.into_iter().map(|(_, (span, _, p_name, res))| {
-                let id = self.resolver.next_node_id();
+                let id = self.next_node_id();
                 let ident = Ident::new(p_name.ident().name, span);
                 let l = self.new_named_lifetime_with_res(id, span, ident, res);
                 hir::GenericArg::Lifetime(l)
@@ -1817,10 +1815,11 @@
         )
     }
 
+    #[instrument(level = "trace", skip(self))]
     fn lower_param_bound(
         &mut self,
         tpb: &GenericBound,
-        itctx: ImplTraitContext<'_, 'hir>,
+        itctx: ImplTraitContext,
     ) -> hir::GenericBound<'hir> {
         match tpb {
             GenericBound::Trait(p, modifier) => hir::GenericBound::Trait(
@@ -1836,10 +1835,7 @@
     fn lower_lifetime(&mut self, l: &Lifetime) -> hir::Lifetime {
         let span = self.lower_span(l.ident.span);
         let ident = self.lower_ident(l.ident);
-        let res = self
-            .resolver
-            .get_lifetime_res(l.id)
-            .unwrap_or_else(|| panic!("Missing resolution for lifetime {:?} at {:?}", l, span));
+        let res = self.resolver.get_lifetime_res(l.id).unwrap_or(LifetimeRes::Error);
         self.new_named_lifetime_with_res(l.id, span, ident, res)
     }
 
@@ -1853,88 +1849,85 @@
     ) -> hir::Lifetime {
         debug!(?self.captured_lifetimes);
         let name = match res {
-            LifetimeRes::Param { param, binder } => {
+            LifetimeRes::Param { mut param, binder } => {
                 debug_assert_ne!(ident.name, kw::UnderscoreLifetime);
                 let p_name = ParamName::Plain(ident);
-                if let Some(LifetimeCaptureContext { parent_def_id, captures, binders_to_ignore }) =
-                    &mut self.captured_lifetimes
-                    && !binders_to_ignore.contains(&binder)
-                {
-                    match captures.entry(param) {
-                        Entry::Occupied(_) => {}
-                        Entry::Vacant(v) => {
-                            let p_id = self.resolver.next_node_id();
-                            self.resolver.create_def(
-                                *parent_def_id,
-                                p_id,
-                                DefPathData::LifetimeNs(p_name.ident().name),
-                                ExpnId::root(),
-                                span.with_parent(None),
-                            );
+                if let Some(mut captured_lifetimes) = self.captured_lifetimes.take() {
+                    if !captured_lifetimes.binders_to_ignore.contains(&binder) {
+                        match captured_lifetimes.captures.entry(param) {
+                            Entry::Occupied(o) => param = self.local_def_id(o.get().1),
+                            Entry::Vacant(v) => {
+                                let p_id = self.next_node_id();
+                                let p_def_id = self.create_def(
+                                    captured_lifetimes.parent_def_id,
+                                    p_id,
+                                    DefPathData::LifetimeNs(p_name.ident().name),
+                                );
 
-                            v.insert((span, p_id, p_name, res));
+                                v.insert((span, p_id, p_name, res));
+                                param = p_def_id;
+                            }
                         }
                     }
+
+                    self.captured_lifetimes = Some(captured_lifetimes);
                 }
-                hir::LifetimeName::Param(p_name)
+                hir::LifetimeName::Param(param, p_name)
             }
-            LifetimeRes::Fresh { mut param, binder } => {
+            LifetimeRes::Fresh { param, binder } => {
                 debug_assert_eq!(ident.name, kw::UnderscoreLifetime);
-                if let Some(LifetimeCaptureContext { parent_def_id, captures, binders_to_ignore }) =
-                    &mut self.captured_lifetimes
-                    && !binders_to_ignore.contains(&binder)
-                {
-                    match captures.entry(param) {
-                        Entry::Occupied(o) => param = self.resolver.local_def_id(o.get().1),
-                        Entry::Vacant(v) => {
-                            let p_id = self.resolver.next_node_id();
-                            let p_def_id = self.resolver.create_def(
-                                *parent_def_id,
-                                p_id,
-                                DefPathData::LifetimeNs(kw::UnderscoreLifetime),
-                                ExpnId::root(),
-                                span.with_parent(None),
-                            );
+                let mut param = self.local_def_id(param);
+                if let Some(mut captured_lifetimes) = self.captured_lifetimes.take() {
+                    if !captured_lifetimes.binders_to_ignore.contains(&binder) {
+                        match captured_lifetimes.captures.entry(param) {
+                            Entry::Occupied(o) => param = self.local_def_id(o.get().1),
+                            Entry::Vacant(v) => {
+                                let p_id = self.next_node_id();
+                                let p_def_id = self.create_def(
+                                    captured_lifetimes.parent_def_id,
+                                    p_id,
+                                    DefPathData::LifetimeNs(kw::UnderscoreLifetime),
+                                );
 
-                            let p_name = ParamName::Fresh(param);
-                            v.insert((span, p_id, p_name, res));
-                            param = p_def_id;
+                                v.insert((span, p_id, ParamName::Fresh, res));
+                                param = p_def_id;
+                            }
                         }
                     }
+
+                    self.captured_lifetimes = Some(captured_lifetimes);
                 }
-                let p_name = ParamName::Fresh(param);
-                hir::LifetimeName::Param(p_name)
+                hir::LifetimeName::Param(param, ParamName::Fresh)
             }
             LifetimeRes::Anonymous { binder, elided } => {
-                let l_name = if elided {
+                let mut l_name = None;
+                if let Some(mut captured_lifetimes) = self.captured_lifetimes.take() {
+                    if !captured_lifetimes.binders_to_ignore.contains(&binder) {
+                        let p_id = self.next_node_id();
+                        let p_def_id = self.create_def(
+                            captured_lifetimes.parent_def_id,
+                            p_id,
+                            DefPathData::LifetimeNs(kw::UnderscoreLifetime),
+                        );
+                        captured_lifetimes
+                            .captures
+                            .insert(p_def_id, (span, p_id, ParamName::Fresh, res));
+                        l_name = Some(hir::LifetimeName::Param(p_def_id, ParamName::Fresh));
+                    }
+                    self.captured_lifetimes = Some(captured_lifetimes);
+                };
+                l_name.unwrap_or(if elided {
                     hir::LifetimeName::Implicit
                 } else {
                     hir::LifetimeName::Underscore
-                };
-                if let Some(LifetimeCaptureContext { parent_def_id, captures, binders_to_ignore }) =
-                    &mut self.captured_lifetimes
-                    && !binders_to_ignore.contains(&binder)
-                {
-                    let p_id = self.resolver.next_node_id();
-                    let p_def_id = self.resolver.create_def(
-                        *parent_def_id,
-                        p_id,
-                        DefPathData::LifetimeNs(kw::UnderscoreLifetime),
-                        ExpnId::root(),
-                        span.with_parent(None),
-                    );
-                    let p_name = ParamName::Fresh(p_def_id);
-                    captures.insert(p_def_id, (span, p_id, p_name, res));
-                    hir::LifetimeName::Param(p_name)
-                } else {
-                    l_name
-                }
+                })
             }
             LifetimeRes::Static => hir::LifetimeName::Static,
             LifetimeRes::Error => hir::LifetimeName::Error,
             res => panic!("Unexpected lifetime resolution {:?} for {:?} at {:?}", res, ident, span),
         };
         debug!(?self.captured_lifetimes);
+        debug!(?name);
         hir::Lifetime { hir_id: self.lower_node_id(id), span: self.lower_span(span), name }
     }
 
@@ -1949,17 +1942,37 @@
         self.arena.alloc_from_iter(self.lower_generic_params_mut(params))
     }
 
+    #[instrument(level = "trace", skip(self))]
     fn lower_generic_param(&mut self, param: &GenericParam) -> hir::GenericParam<'hir> {
-        let (name, kind) = match param.kind {
+        let (name, kind) = self.lower_generic_param_kind(param);
+
+        let hir_id = self.lower_node_id(param.id);
+        self.lower_attrs(hir_id, &param.attrs);
+        hir::GenericParam {
+            hir_id,
+            name,
+            span: self.lower_span(param.span()),
+            pure_wrt_drop: self.sess.contains_name(&param.attrs, sym::may_dangle),
+            kind,
+            colon_span: param.colon_span.map(|s| self.lower_span(s)),
+        }
+    }
+
+    fn lower_generic_param_kind(
+        &mut self,
+        param: &GenericParam,
+    ) -> (hir::ParamName, hir::GenericParamKind<'hir>) {
+        match param.kind {
             GenericParamKind::Lifetime => {
-                let param_name = if param.ident.name == kw::StaticLifetime
-                    || param.ident.name == kw::UnderscoreLifetime
-                {
-                    ParamName::Error
-                } else {
-                    let ident = self.lower_ident(param.ident);
-                    ParamName::Plain(ident)
-                };
+                // AST resolution emitted an error on those parameters, so we lower them using
+                // `ParamName::Error`.
+                let param_name =
+                    if let Some(LifetimeRes::Error) = self.resolver.get_lifetime_res(param.id) {
+                        ParamName::Error
+                    } else {
+                        let ident = self.lower_ident(param.ident);
+                        ParamName::Plain(ident)
+                    };
                 let kind =
                     hir::GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Explicit };
 
@@ -1983,29 +1996,10 @@
                     hir::GenericParamKind::Const { ty, default },
                 )
             }
-        };
-        let name = match name {
-            hir::ParamName::Plain(ident) => hir::ParamName::Plain(self.lower_ident(ident)),
-            name => name,
-        };
-
-        let hir_id = self.lower_node_id(param.id);
-        self.lower_attrs(hir_id, &param.attrs);
-        hir::GenericParam {
-            hir_id,
-            name,
-            span: self.lower_span(param.span()),
-            pure_wrt_drop: self.sess.contains_name(&param.attrs, sym::may_dangle),
-            kind,
-            colon_span: param.colon_span.map(|s| self.lower_span(s)),
         }
     }
 
-    fn lower_trait_ref(
-        &mut self,
-        p: &TraitRef,
-        itctx: ImplTraitContext<'_, 'hir>,
-    ) -> hir::TraitRef<'hir> {
+    fn lower_trait_ref(&mut self, p: &TraitRef, itctx: ImplTraitContext) -> hir::TraitRef<'hir> {
         let path = match self.lower_qpath(p.ref_id, &None, &p.path, ParamMode::Explicit, itctx) {
             hir::QPath::Resolved(None, path) => path,
             qpath => panic!("lower_trait_ref: unexpected QPath `{:?}`", qpath),
@@ -2017,25 +2011,26 @@
     fn lower_poly_trait_ref(
         &mut self,
         p: &PolyTraitRef,
-        mut itctx: ImplTraitContext<'_, 'hir>,
+        itctx: ImplTraitContext,
     ) -> hir::PolyTraitRef<'hir> {
-        let bound_generic_params = self.lower_generic_params(&p.bound_generic_params);
-
-        let trait_ref = self.with_lifetime_binder(p.trait_ref.ref_id, |this| {
-            this.lower_trait_ref(&p.trait_ref, itctx.reborrow())
-        });
-
-        hir::PolyTraitRef { bound_generic_params, trait_ref, span: self.lower_span(p.span) }
+        self.with_lifetime_binder(
+            p.trait_ref.ref_id,
+            &p.bound_generic_params,
+            |this, bound_generic_params| {
+                let trait_ref = this.lower_trait_ref(&p.trait_ref, itctx);
+                hir::PolyTraitRef { bound_generic_params, trait_ref, span: this.lower_span(p.span) }
+            },
+        )
     }
 
-    fn lower_mt(&mut self, mt: &MutTy, itctx: ImplTraitContext<'_, 'hir>) -> hir::MutTy<'hir> {
+    fn lower_mt(&mut self, mt: &MutTy, itctx: ImplTraitContext) -> hir::MutTy<'hir> {
         hir::MutTy { ty: self.lower_ty(&mt.ty, itctx), mutbl: mt.mutbl }
     }
 
     fn lower_param_bounds(
         &mut self,
         bounds: &[GenericBound],
-        itctx: ImplTraitContext<'_, 'hir>,
+        itctx: ImplTraitContext,
     ) -> hir::GenericBounds<'hir> {
         self.arena.alloc_from_iter(self.lower_param_bounds_mut(bounds, itctx))
     }
@@ -2043,9 +2038,50 @@
     fn lower_param_bounds_mut<'s>(
         &'s mut self,
         bounds: &'s [GenericBound],
-        mut itctx: ImplTraitContext<'s, 'hir>,
+        itctx: ImplTraitContext,
     ) -> impl Iterator<Item = hir::GenericBound<'hir>> + Captures<'s> + Captures<'a> {
-        bounds.iter().map(move |bound| self.lower_param_bound(bound, itctx.reborrow()))
+        bounds.iter().map(move |bound| self.lower_param_bound(bound, itctx))
+    }
+
+    fn lower_generic_and_bounds(
+        &mut self,
+        node_id: NodeId,
+        span: Span,
+        ident: Ident,
+        bounds: &[GenericBound],
+    ) -> (hir::GenericParam<'hir>, Option<hir::WherePredicate<'hir>>, hir::TyKind<'hir>) {
+        // Add a definition for the in-band `Param`.
+        let def_id = self.local_def_id(node_id);
+
+        let hir_bounds = self.lower_param_bounds(bounds, ImplTraitContext::Universal);
+        // Set the name to `impl Bound1 + Bound2`.
+        let param = hir::GenericParam {
+            hir_id: self.lower_node_id(node_id),
+            name: ParamName::Plain(self.lower_ident(ident)),
+            pure_wrt_drop: false,
+            span: self.lower_span(span),
+            kind: hir::GenericParamKind::Type { default: None, synthetic: true },
+            colon_span: None,
+        };
+
+        let preds = self.lower_generic_bound_predicate(
+            ident,
+            node_id,
+            &GenericParamKind::Type { default: None },
+            hir_bounds,
+            hir::PredicateOrigin::ImplTrait,
+        );
+
+        let ty = hir::TyKind::Path(hir::QPath::Resolved(
+            None,
+            self.arena.alloc(hir::Path {
+                span: self.lower_span(span),
+                res: Res::Def(DefKind::TyParam, def_id.to_def_id()),
+                segments: arena_vec![self; hir::PathSegment::from_ident(self.lower_ident(ident))],
+            }),
+        ));
+
+        (param, preds, ty)
     }
 
     /// Lowers a block directly to an expression, presuming that it
diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs
index 2c33176..bd2e76e 100644
--- a/compiler/rustc_ast_lowering/src/pat.rs
+++ b/compiler/rustc_ast_lowering/src/pat.rs
@@ -1,6 +1,6 @@
-use crate::ImplTraitPosition;
-
+use super::ResolverAstLoweringExt;
 use super::{ImplTraitContext, LoweringContext, ParamMode};
+use crate::ImplTraitPosition;
 
 use rustc_ast::ptr::P;
 use rustc_ast::*;
@@ -12,11 +12,11 @@
 use rustc_span::{source_map::Spanned, Span};
 
 impl<'a, 'hir> LoweringContext<'a, 'hir> {
-    crate fn lower_pat(&mut self, pattern: &Pat) -> &'hir hir::Pat<'hir> {
+    pub(crate) fn lower_pat(&mut self, pattern: &Pat) -> &'hir hir::Pat<'hir> {
         self.arena.alloc(self.lower_pat_mut(pattern))
     }
 
-    crate fn lower_pat_mut(&mut self, mut pattern: &Pat) -> hir::Pat<'hir> {
+    pub(crate) fn lower_pat_mut(&mut self, mut pattern: &Pat) -> hir::Pat<'hir> {
         ensure_sufficient_stack(|| {
             // loop here to avoid recursion
             let node = loop {
@@ -139,7 +139,7 @@
                         .span_suggestion_verbose(
                             sp,
                             &format!("if you don't need to use the contents of {}, discard the tuple's remaining fields", ident),
-                            "..".to_string(),
+                            "..",
                             Applicability::MaybeIncorrect,
                         )
                         .emit();
@@ -290,7 +290,7 @@
     }
 
     /// Emit a friendly error for extra `..` patterns in a tuple/tuple struct/slice pattern.
-    crate fn ban_extra_rest_pat(&self, sp: Span, prev_sp: Span, ctx: &str) {
+    pub(crate) fn ban_extra_rest_pat(&self, sp: Span, prev_sp: Span, ctx: &str) {
         self.diagnostic()
             .struct_span_err(sp, &format!("`..` can only be used once per {} pattern", ctx))
             .span_label(sp, &format!("can only be used once per {} pattern", ctx))
diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs
index 3c9399c..52ba5da 100644
--- a/compiler/rustc_ast_lowering/src/path.rs
+++ b/compiler/rustc_ast_lowering/src/path.rs
@@ -1,5 +1,6 @@
 use crate::ImplTraitPosition;
 
+use super::ResolverAstLoweringExt;
 use super::{GenericArgsCtor, LifetimeRes, ParenthesizedGenericArgs};
 use super::{ImplTraitContext, LoweringContext, ParamMode};
 
@@ -15,17 +16,17 @@
 use tracing::debug;
 
 impl<'a, 'hir> LoweringContext<'a, 'hir> {
-    crate fn lower_qpath(
+    #[instrument(level = "trace", skip(self))]
+    pub(crate) fn lower_qpath(
         &mut self,
         id: NodeId,
         qself: &Option<QSelf>,
         p: &Path,
         param_mode: ParamMode,
-        mut itctx: ImplTraitContext<'_, 'hir>,
+        itctx: ImplTraitContext,
     ) -> hir::QPath<'hir> {
-        debug!("lower_qpath(id: {:?}, qself: {:?}, p: {:?})", id, qself, p);
         let qself_position = qself.as_ref().map(|q| q.position);
-        let qself = qself.as_ref().map(|q| self.lower_ty(&q.ty, itctx.reborrow()));
+        let qself = qself.as_ref().map(|q| self.lower_ty(&q.ty, itctx));
 
         let partial_res =
             self.resolver.get_partial_res(id).unwrap_or_else(|| PartialRes::new(Res::Err));
@@ -70,7 +71,7 @@
                         segment,
                         param_mode,
                         parenthesized_generic_args,
-                        itctx.reborrow(),
+                        itctx,
                     )
                 },
             )),
@@ -116,7 +117,7 @@
                 segment,
                 param_mode,
                 ParenthesizedGenericArgs::Err,
-                itctx.reborrow(),
+                itctx,
             ));
             let qpath = hir::QPath::TypeRelative(ty, hir_segment);
 
@@ -142,7 +143,7 @@
         );
     }
 
-    crate fn lower_path_extra(
+    pub(crate) fn lower_path_extra(
         &mut self,
         res: Res,
         p: &Path,
@@ -163,7 +164,7 @@
         })
     }
 
-    crate fn lower_path(
+    pub(crate) fn lower_path(
         &mut self,
         id: NodeId,
         p: &Path,
@@ -174,13 +175,13 @@
         self.lower_path_extra(res, p, param_mode)
     }
 
-    crate fn lower_path_segment(
+    pub(crate) fn lower_path_segment(
         &mut self,
         path_span: Span,
         segment: &PathSegment,
         param_mode: ParamMode,
         parenthesized_generic_args: ParenthesizedGenericArgs,
-        itctx: ImplTraitContext<'_, 'hir>,
+        itctx: ImplTraitContext,
     ) -> hir::PathSegment<'hir> {
         debug!("path_span: {:?}, lower_path_segment(segment: {:?})", path_span, segment,);
         let (mut generic_args, infer_args) = if let Some(ref generic_args) = segment.args {
@@ -190,31 +191,36 @@
                     self.lower_angle_bracketed_parameter_data(data, param_mode, itctx)
                 }
                 GenericArgs::Parenthesized(ref data) => match parenthesized_generic_args {
-                    ParenthesizedGenericArgs::Ok => {
-                        self.lower_parenthesized_parameter_data(segment.id, data)
-                    }
+                    ParenthesizedGenericArgs::Ok => self.lower_parenthesized_parameter_data(data),
                     ParenthesizedGenericArgs::Err => {
                         let mut err = struct_span_err!(self.sess, data.span, E0214, "{}", msg);
                         err.span_label(data.span, "only `Fn` traits may use parentheses");
-                        if let Ok(snippet) = self.sess.source_map().span_to_snippet(data.span) {
-                            // Do not suggest going from `Trait()` to `Trait<>`
-                            if !data.inputs.is_empty() {
-                                // Suggest replacing `(` and `)` with `<` and `>`
-                                // The snippet may be missing the closing `)`, skip that case
-                                if snippet.ends_with(')') {
-                                    if let Some(split) = snippet.find('(') {
-                                        let trait_name = &snippet[0..split];
-                                        let args = &snippet[split + 1..snippet.len() - 1];
-                                        err.span_suggestion(
-                                            data.span,
-                                            "use angle brackets instead",
-                                            format!("{}<{}>", trait_name, args),
-                                            Applicability::MaybeIncorrect,
-                                        );
-                                    }
-                                }
-                            }
-                        };
+                        // Suggest replacing parentheses with angle brackets `Trait(params...)` to `Trait<params...>`
+                        if !data.inputs.is_empty() {
+                            // Start of the span to the 1st character of 1st argument
+                            let open_param = data.inputs_span.shrink_to_lo().to(data
+                                .inputs
+                                .first()
+                                .unwrap()
+                                .span
+                                .shrink_to_lo());
+                            // Last character position of last argument to the end of the span
+                            let close_param = data
+                                .inputs
+                                .last()
+                                .unwrap()
+                                .span
+                                .shrink_to_hi()
+                                .to(data.inputs_span.shrink_to_hi());
+                            err.multipart_suggestion(
+                                &format!("use angle brackets instead",),
+                                vec![
+                                    (open_param, String::from("<")),
+                                    (close_param, String::from(">")),
+                                ],
+                                Applicability::MaybeIncorrect,
+                            );
+                        }
                         err.emit();
                         (
                             self.lower_angle_bracketed_parameter_data(
@@ -318,7 +324,7 @@
         &mut self,
         data: &AngleBracketedArgs,
         param_mode: ParamMode,
-        mut itctx: ImplTraitContext<'_, 'hir>,
+        itctx: ImplTraitContext,
     ) -> (GenericArgsCtor<'hir>, bool) {
         let has_non_lt_args = data.args.iter().any(|arg| match arg {
             AngleBracketedArg::Arg(ast::GenericArg::Lifetime(_))
@@ -329,14 +335,12 @@
             .args
             .iter()
             .filter_map(|arg| match arg {
-                AngleBracketedArg::Arg(arg) => Some(self.lower_generic_arg(arg, itctx.reborrow())),
+                AngleBracketedArg::Arg(arg) => Some(self.lower_generic_arg(arg, itctx)),
                 AngleBracketedArg::Constraint(_) => None,
             })
             .collect();
         let bindings = self.arena.alloc_from_iter(data.args.iter().filter_map(|arg| match arg {
-            AngleBracketedArg::Constraint(c) => {
-                Some(self.lower_assoc_ty_constraint(c, itctx.reborrow()))
-            }
+            AngleBracketedArg::Constraint(c) => Some(self.lower_assoc_ty_constraint(c, itctx)),
             AngleBracketedArg::Arg(_) => None,
         }));
         let ctor = GenericArgsCtor { args, bindings, parenthesized: false, span: data.span };
@@ -345,7 +349,6 @@
 
     fn lower_parenthesized_parameter_data(
         &mut self,
-        id: NodeId,
         data: &ParenthesizedArgs,
     ) -> (GenericArgsCtor<'hir>, bool) {
         // Switch to `PassThrough` mode for anonymous lifetimes; this
@@ -353,35 +356,31 @@
         // a hidden lifetime parameter. This is needed for backwards
         // compatibility, even in contexts like an impl header where
         // we generally don't permit such things (see #51008).
-        self.with_lifetime_binder(id, |this| {
-            let ParenthesizedArgs { span, inputs, inputs_span, output } = data;
-            let inputs = this.arena.alloc_from_iter(inputs.iter().map(|ty| {
-                this.lower_ty_direct(
-                    ty,
-                    ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitParam),
-                )
-            }));
-            let output_ty = match output {
-                FnRetTy::Ty(ty) => this
-                    .lower_ty(&ty, ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitReturn)),
-                FnRetTy::Default(_) => this.arena.alloc(this.ty_tup(*span, &[])),
-            };
-            let args = smallvec![GenericArg::Type(this.ty_tup(*inputs_span, inputs))];
-            let binding = this.output_ty_binding(output_ty.span, output_ty);
-            (
-                GenericArgsCtor {
-                    args,
-                    bindings: arena_vec![this; binding],
-                    parenthesized: true,
-                    span: data.inputs_span,
-                },
-                false,
-            )
-        })
+        let ParenthesizedArgs { span, inputs, inputs_span, output } = data;
+        let inputs = self.arena.alloc_from_iter(inputs.iter().map(|ty| {
+            self.lower_ty_direct(ty, ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitParam))
+        }));
+        let output_ty = match output {
+            FnRetTy::Ty(ty) => {
+                self.lower_ty(&ty, ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitReturn))
+            }
+            FnRetTy::Default(_) => self.arena.alloc(self.ty_tup(*span, &[])),
+        };
+        let args = smallvec![GenericArg::Type(self.ty_tup(*inputs_span, inputs))];
+        let binding = self.output_ty_binding(output_ty.span, output_ty);
+        (
+            GenericArgsCtor {
+                args,
+                bindings: arena_vec![self; binding],
+                parenthesized: true,
+                span: data.inputs_span,
+            },
+            false,
+        )
     }
 
     /// An associated type binding `Output = $ty`.
-    crate fn output_ty_binding(
+    pub(crate) fn output_ty_binding(
         &mut self,
         span: Span,
         ty: &'hir hir::Ty<'hir>,
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index 058a0f9..503bdba 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -420,7 +420,15 @@
             .iter()
             .flat_map(|i| i.attrs.as_ref())
             .filter(|attr| {
-                let arr = [sym::allow, sym::cfg, sym::cfg_attr, sym::deny, sym::forbid, sym::warn];
+                let arr = [
+                    sym::allow,
+                    sym::cfg,
+                    sym::cfg_attr,
+                    sym::deny,
+                    sym::expect,
+                    sym::forbid,
+                    sym::warn,
+                ];
                 !arr.contains(&attr.name_or_empty()) && rustc_attr::is_builtin_attr(attr)
             })
             .for_each(|attr| {
@@ -435,7 +443,7 @@
                 } else {
                     self.err_handler().span_err(
                         attr.span,
-                        "allow, cfg, cfg_attr, deny, \
+                        "allow, cfg, cfg_attr, deny, expect, \
                 forbid, and warn are the only allowed built-in attributes in function parameters",
                     );
                 }
@@ -480,7 +488,7 @@
             .span_suggestion(
                 replace_span,
                 &format!("provide a definition for the {}", ctx),
-                sugg.to_string(),
+                sugg,
                 Applicability::HasPlaceholders,
             )
             .emit();
@@ -514,7 +522,7 @@
                 .span_suggestion(
                     span,
                     &format!("remove the {}", remove_descr),
-                    String::new(),
+                    "",
                     Applicability::MaybeIncorrect,
                 )
                 .span_label(self.current_extern_span(), "`extern` block begins here")
@@ -562,7 +570,7 @@
             .span_suggestion(
                 body.span,
                 "remove the invalid body",
-                ";".to_string(),
+                ";",
                 Applicability::MaybeIncorrect,
             )
             .help(
@@ -591,7 +599,7 @@
                 .span_suggestion_verbose(
                     span.until(ident.span.shrink_to_lo()),
                     "remove the qualifiers",
-                    "fn ".to_string(),
+                    "fn ",
                     Applicability::MaybeIncorrect,
                 )
                 .emit();
@@ -695,7 +703,7 @@
             .span_suggestion(
                 generics.span,
                 "remove the parameters",
-                String::new(),
+                "",
                 Applicability::MachineApplicable,
             )
             .emit();
@@ -713,7 +721,7 @@
         .span_suggestion(
             span,
             "remove the super traits or lifetime bounds",
-            String::new(),
+            "",
             Applicability::MachineApplicable,
         )
         .emit();
@@ -745,7 +753,7 @@
             .span_suggestion(
                 total_span,
                 "remove these associated items",
-                String::new(),
+                "",
                 Applicability::MachineApplicable,
             )
             .span_label(ident_span, "auto trait cannot have associated items")
@@ -985,7 +993,7 @@
             err.span_suggestion(
                 span,
                 "reorder the parameters: lifetimes, then consts and types",
-                ordered_params.clone(),
+                &ordered_params,
                 Applicability::MachineApplicable,
             );
             err.emit();
@@ -1070,7 +1078,7 @@
         visit::walk_label(self, label);
     }
 
-    fn visit_lifetime(&mut self, lifetime: &'a Lifetime) {
+    fn visit_lifetime(&mut self, lifetime: &'a Lifetime, _: visit::LifetimeCtxt) {
         self.check_lifetime(lifetime.ident);
         visit::walk_lifetime(self, lifetime);
     }
@@ -1463,10 +1471,9 @@
         if let GenericBound::Trait(ref poly, modify) = *bound {
             match (ctxt, modify) {
                 (BoundKind::SuperTraits, TraitBoundModifier::Maybe) => {
-                    let mut err = self.err_handler().struct_span_err(
-                        poly.span,
-                        &format!("`?Trait` is not permitted in supertraits"),
-                    );
+                    let mut err = self
+                        .err_handler()
+                        .struct_span_err(poly.span, "`?Trait` is not permitted in supertraits");
                     let path_str = pprust::path_to_string(&poly.trait_ref.path);
                     err.note(&format!("traits are `?{}` by default", path_str));
                     err.emit();
@@ -1474,7 +1481,7 @@
                 (BoundKind::TraitObject, TraitBoundModifier::Maybe) => {
                     let mut err = self.err_handler().struct_span_err(
                         poly.span,
-                        &format!("`?Trait` is not permitted in trait object types"),
+                        "`?Trait` is not permitted in trait object types",
                     );
                     err.emit();
                 }
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index 0e8af54..37c4f66 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -113,6 +113,14 @@
                     "rust-call ABI is subject to change"
                 );
             }
+            "rust-cold" => {
+                gate_feature_post!(
+                    &self,
+                    rust_cold_cc,
+                    span,
+                    "rust-cold is experimental and subject to change"
+                );
+            }
             "ptx-kernel" => {
                 gate_feature_post!(
                     &self,
@@ -393,44 +401,17 @@
                     let msg = "`#[doc(keyword)]` is meant for internal use only";
                     gate_feature_post!(self, rustdoc_internals, attr.span, msg);
                 }
-            }
-        }
 
-        // Check for unstable modifiers on `#[link(..)]` attribute
-        if attr.has_name(sym::link) {
-            for nested_meta in attr.meta_item_list().unwrap_or_default() {
-                if nested_meta.has_name(sym::modifiers) {
-                    if let Some(modifiers) = nested_meta.value_str() {
-                        for modifier in modifiers.as_str().split(',') {
-                            if let Some(modifier) = modifier.strip_prefix(&['+', '-']) {
-                                macro_rules! gate_modifier { ($($name:literal => $feature:ident)*) => {
-                                    $(if modifier == $name {
-                                        let msg = concat!("`#[link(modifiers=\"", $name, "\")]` is unstable");
-                                        gate_feature_post!(
-                                            self,
-                                            $feature,
-                                            nested_meta.name_value_literal_span().unwrap(),
-                                            msg
-                                        );
-                                    })*
-                                }}
-
-                                gate_modifier!(
-                                    "bundle" => native_link_modifiers_bundle
-                                    "verbatim" => native_link_modifiers_verbatim
-                                    "as-needed" => native_link_modifiers_as_needed
-                                );
-                            }
-                        }
-                    }
+                if nested_meta.has_name(sym::tuple_variadic) {
+                    let msg = "`#[doc(tuple_variadic)]` is meant for internal use only";
+                    gate_feature_post!(self, rustdoc_internals, attr.span, msg);
                 }
             }
         }
 
         // Emit errors for non-staged-api crates.
         if !self.features.staged_api {
-            if attr.has_name(sym::rustc_deprecated)
-                || attr.has_name(sym::unstable)
+            if attr.has_name(sym::unstable)
                 || attr.has_name(sym::stable)
                 || attr.has_name(sym::rustc_const_unstable)
                 || attr.has_name(sym::rustc_const_stable)
@@ -728,18 +709,6 @@
         }
         visit::walk_assoc_item(self, i, ctxt)
     }
-
-    fn visit_vis(&mut self, vis: &'a ast::Visibility) {
-        if let ast::VisibilityKind::Crate(ast::CrateSugar::JustCrate) = vis.kind {
-            gate_feature_post!(
-                &self,
-                crate_visibility_modifier,
-                vis.span,
-                "`crate` visibility modifier is experimental"
-            );
-        }
-        visit::walk_vis(self, vis)
-    }
 }
 
 pub fn check_crate(krate: &ast::Crate, sess: &Session) {
@@ -801,7 +770,6 @@
 
     gate_all!(trait_alias, "trait aliases are experimental");
     gate_all!(associated_type_bounds, "associated type bounds are unstable");
-    gate_all!(crate_visibility_modifier, "`crate` visibility modifier is experimental");
     gate_all!(decl_macro, "`macro` is experimental");
     gate_all!(box_patterns, "box pattern syntax is experimental");
     gate_all!(exclusive_range_pattern, "exclusive range pattern syntax is experimental");
@@ -859,7 +827,7 @@
                 err.span_suggestion(
                     attr.span,
                     "remove the attribute",
-                    String::new(),
+                    "",
                     Applicability::MachineApplicable,
                 );
             }
diff --git a/compiler/rustc_ast_passes/src/node_count.rs b/compiler/rustc_ast_passes/src/node_count.rs
index 48b7980..ee166f7 100644
--- a/compiler/rustc_ast_passes/src/node_count.rs
+++ b/compiler/rustc_ast_passes/src/node_count.rs
@@ -106,7 +106,7 @@
         self.count += 1;
         walk_variant(self, v)
     }
-    fn visit_lifetime(&mut self, lifetime: &Lifetime) {
+    fn visit_lifetime(&mut self, lifetime: &Lifetime, _: visit::LifetimeCtxt) {
         self.count += 1;
         walk_lifetime(self, lifetime)
     }
diff --git a/compiler/rustc_ast_pretty/src/lib.rs b/compiler/rustc_ast_pretty/src/lib.rs
index 95beccb..7917883 100644
--- a/compiler/rustc_ast_pretty/src/lib.rs
+++ b/compiler/rustc_ast_pretty/src/lib.rs
@@ -1,5 +1,4 @@
 #![feature(associated_type_bounds)]
-#![feature(crate_visibility_modifier)]
 #![feature(box_patterns)]
 #![feature(with_negative_coherence)]
 #![recursion_limit = "256"]
diff --git a/compiler/rustc_ast_pretty/src/pprust/mod.rs b/compiler/rustc_ast_pretty/src/pprust/mod.rs
index d2e2fd5..ac9e7d0 100644
--- a/compiler/rustc_ast_pretty/src/pprust/mod.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/mod.rs
@@ -4,42 +4,12 @@
 pub mod state;
 pub use state::{print_crate, AnnNode, Comments, PpAnn, PrintState, State};
 
+use rustc_ast as ast;
 use rustc_ast::token::{Nonterminal, Token, TokenKind};
 use rustc_ast::tokenstream::{TokenStream, TokenTree};
-use rustc_ast::{self as ast, AstDeref};
 
 use std::borrow::Cow;
 
-pub trait AstPrettyPrint {
-    fn pretty_print(&self) -> String;
-}
-
-impl<T: AstDeref<Target: AstPrettyPrint>> AstPrettyPrint for T {
-    fn pretty_print(&self) -> String {
-        self.ast_deref().pretty_print()
-    }
-}
-
-macro_rules! impl_ast_pretty_print {
-    ($($T:ty => $method:ident),+ $(,)?) => {
-        $(
-            impl AstPrettyPrint for $T {
-                fn pretty_print(&self) -> String {
-                    State::new().$method(self)
-                }
-            }
-        )+
-    };
-}
-
-impl_ast_pretty_print! {
-    ast::Item => item_to_string,
-    ast::AssocItem => assoc_item_to_string,
-    ast::ForeignItem => foreign_item_to_string,
-    ast::Expr => expr_to_string,
-    ast::Stmt => stmt_to_string,
-}
-
 pub fn nonterminal_to_string(nt: &Nonterminal) -> String {
     State::new().nonterminal_to_string(nt)
 }
diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs
index 2fffa52..ad8dbfd 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state.rs
@@ -95,7 +95,7 @@
     ann: &'a (dyn PpAnn + 'a),
 }
 
-crate const INDENT_UNIT: isize = 4;
+pub(crate) const INDENT_UNIT: isize = 4;
 
 /// Requires you to pass an input filename and reader so that
 /// it can scan the input text for comments to copy forward.
@@ -550,9 +550,9 @@
     fn print_tts(&mut self, tts: &TokenStream, convert_dollar_crate: bool) {
         let mut iter = tts.trees().peekable();
         while let Some(tt) = iter.next() {
-            self.print_tt(&tt, convert_dollar_crate);
+            self.print_tt(tt, convert_dollar_crate);
             if let Some(next) = iter.peek() {
-                if tt_prepend_space(next, &tt) {
+                if tt_prepend_space(next, tt) {
                     self.space();
                 }
             }
@@ -814,7 +814,7 @@
     }
 
     fn bounds_to_string(&self, bounds: &[ast::GenericBound]) -> String {
-        Self::to_string(|s| s.print_type_bounds("", bounds))
+        Self::to_string(|s| s.print_type_bounds(bounds))
     }
 
     fn pat_to_string(&self, pat: &ast::Pat) -> String {
@@ -942,8 +942,13 @@
         State { s: pp::Printer::new(), comments: None, ann: &NoAnn }
     }
 
-    crate fn commasep_cmnt<T, F, G>(&mut self, b: Breaks, elts: &[T], mut op: F, mut get_span: G)
-    where
+    pub(crate) fn commasep_cmnt<T, F, G>(
+        &mut self,
+        b: Breaks,
+        elts: &[T],
+        mut op: F,
+        mut get_span: G,
+    ) where
         F: FnMut(&mut State<'_>, &T),
         G: FnMut(&T) -> rustc_span::Span,
     {
@@ -963,7 +968,7 @@
         self.end();
     }
 
-    crate fn commasep_exprs(&mut self, b: Breaks, exprs: &[P<ast::Expr>]) {
+    pub(crate) fn commasep_exprs(&mut self, b: Breaks, exprs: &[P<ast::Expr>]) {
         self.commasep_cmnt(b, exprs, |s, e| s.print_expr(e), |e| e.span)
     }
 
@@ -986,7 +991,12 @@
                     Term::Const(c) => self.print_expr_anon_const(c, &[]),
                 }
             }
-            ast::AssocConstraintKind::Bound { bounds } => self.print_type_bounds(":", &*bounds),
+            ast::AssocConstraintKind::Bound { bounds } => {
+                if !bounds.is_empty() {
+                    self.word_nbsp(":");
+                    self.print_type_bounds(&bounds);
+                }
+            }
         }
     }
 
@@ -1040,11 +1050,14 @@
             }
             ast::TyKind::Path(Some(ref qself), ref path) => self.print_qpath(path, qself, false),
             ast::TyKind::TraitObject(ref bounds, syntax) => {
-                let prefix = if syntax == ast::TraitObjectSyntax::Dyn { "dyn" } else { "" };
-                self.print_type_bounds(prefix, &bounds);
+                if syntax == ast::TraitObjectSyntax::Dyn {
+                    self.word_nbsp("dyn");
+                }
+                self.print_type_bounds(bounds);
             }
             ast::TyKind::ImplTrait(_, ref bounds) => {
-                self.print_type_bounds("impl", &bounds);
+                self.word_nbsp("impl");
+                self.print_type_bounds(bounds);
             }
             ast::TyKind::Array(ref ty, ref length) => {
                 self.word("[");
@@ -1096,7 +1109,7 @@
         self.print_trait_ref(&t.trait_ref)
     }
 
-    crate fn print_stmt(&mut self, st: &ast::Stmt) {
+    pub(crate) fn print_stmt(&mut self, st: &ast::Stmt) {
         self.maybe_print_comment(st.span.lo());
         match st.kind {
             ast::StmtKind::Local(ref loc) => {
@@ -1151,19 +1164,19 @@
         self.maybe_print_trailing_comment(st.span, None)
     }
 
-    crate fn print_block(&mut self, blk: &ast::Block) {
+    pub(crate) fn print_block(&mut self, blk: &ast::Block) {
         self.print_block_with_attrs(blk, &[])
     }
 
-    crate fn print_block_unclosed_indent(&mut self, blk: &ast::Block) {
+    pub(crate) fn print_block_unclosed_indent(&mut self, blk: &ast::Block) {
         self.print_block_maybe_unclosed(blk, &[], false)
     }
 
-    crate fn print_block_with_attrs(&mut self, blk: &ast::Block, attrs: &[ast::Attribute]) {
+    pub(crate) fn print_block_with_attrs(&mut self, blk: &ast::Block, attrs: &[ast::Attribute]) {
         self.print_block_maybe_unclosed(blk, attrs, true)
     }
 
-    crate fn print_block_maybe_unclosed(
+    pub(crate) fn print_block_maybe_unclosed(
         &mut self,
         blk: &ast::Block,
         attrs: &[ast::Attribute],
@@ -1197,7 +1210,7 @@
     }
 
     /// Print a `let pat = expr` expression.
-    crate fn print_let(&mut self, pat: &ast::Pat, expr: &ast::Expr) {
+    pub(crate) fn print_let(&mut self, pat: &ast::Pat, expr: &ast::Expr) {
         self.word("let ");
         self.print_pat(pat);
         self.space();
@@ -1206,7 +1219,7 @@
         self.print_expr_cond_paren(expr, Self::cond_needs_par(expr) || npals())
     }
 
-    crate fn print_mac(&mut self, m: &ast::MacCall) {
+    pub(crate) fn print_mac(&mut self, m: &ast::MacCall) {
         self.print_mac_common(
             Some(MacHeader::Path(&m.path)),
             true,
@@ -1347,7 +1360,7 @@
         self.pclose();
     }
 
-    crate fn print_local_decl(&mut self, loc: &ast::Local) {
+    pub(crate) fn print_local_decl(&mut self, loc: &ast::Local) {
         self.print_pat(&loc.pat);
         if let Some(ref ty) = loc.ty {
             self.word_space(":");
@@ -1355,7 +1368,7 @@
         }
     }
 
-    crate fn print_name(&mut self, name: Symbol) {
+    pub(crate) fn print_name(&mut self, name: Symbol) {
         self.word(name.to_string());
         self.ann.post(self, AnnNode::Name(&name))
     }
@@ -1379,7 +1392,7 @@
         }
     }
 
-    crate fn print_pat(&mut self, pat: &ast::Pat) {
+    pub(crate) fn print_pat(&mut self, pat: &ast::Pat) {
         self.maybe_print_comment(pat.span.lo());
         self.ann.pre(self, AnnNode::Pat(pat));
         /* Pat isn't normalized, but the beauty of it
@@ -1538,64 +1551,51 @@
         }
     }
 
-    crate fn print_asyncness(&mut self, asyncness: ast::Async) {
+    pub(crate) fn print_asyncness(&mut self, asyncness: ast::Async) {
         if asyncness.is_async() {
             self.word_nbsp("async");
         }
     }
 
-    pub fn print_type_bounds(&mut self, prefix: &'static str, bounds: &[ast::GenericBound]) {
-        if !bounds.is_empty() {
-            self.word(prefix);
-            let mut first = true;
-            for bound in bounds {
-                if !(first && prefix.is_empty()) {
-                    self.nbsp();
-                }
-                if first {
-                    first = false;
-                } else {
-                    self.word_space("+");
-                }
+    pub fn print_type_bounds(&mut self, bounds: &[ast::GenericBound]) {
+        let mut first = true;
+        for bound in bounds {
+            if first {
+                first = false;
+            } else {
+                self.nbsp();
+                self.word_space("+");
+            }
 
-                match bound {
-                    GenericBound::Trait(tref, modifier) => {
-                        if modifier == &TraitBoundModifier::Maybe {
-                            self.word("?");
-                        }
-                        self.print_poly_trait_ref(tref);
+            match bound {
+                GenericBound::Trait(tref, modifier) => {
+                    if modifier == &TraitBoundModifier::Maybe {
+                        self.word("?");
                     }
-                    GenericBound::Outlives(lt) => self.print_lifetime(*lt),
+                    self.print_poly_trait_ref(tref);
                 }
+                GenericBound::Outlives(lt) => self.print_lifetime(*lt),
             }
         }
     }
 
-    crate fn print_lifetime(&mut self, lifetime: ast::Lifetime) {
+    pub(crate) fn print_lifetime(&mut self, lifetime: ast::Lifetime) {
         self.print_name(lifetime.ident.name)
     }
 
-    crate fn print_lifetime_bounds(
-        &mut self,
-        lifetime: ast::Lifetime,
-        bounds: &ast::GenericBounds,
-    ) {
-        self.print_lifetime(lifetime);
-        if !bounds.is_empty() {
-            self.word(": ");
-            for (i, bound) in bounds.iter().enumerate() {
-                if i != 0 {
-                    self.word(" + ");
-                }
-                match bound {
-                    ast::GenericBound::Outlives(lt) => self.print_lifetime(*lt),
-                    _ => panic!(),
-                }
+    pub(crate) fn print_lifetime_bounds(&mut self, bounds: &ast::GenericBounds) {
+        for (i, bound) in bounds.iter().enumerate() {
+            if i != 0 {
+                self.word(" + ");
+            }
+            match bound {
+                ast::GenericBound::Outlives(lt) => self.print_lifetime(*lt),
+                _ => panic!(),
             }
         }
     }
 
-    crate fn print_generic_params(&mut self, generic_params: &[ast::GenericParam]) {
+    pub(crate) fn print_generic_params(&mut self, generic_params: &[ast::GenericParam]) {
         if generic_params.is_empty() {
             return;
         }
@@ -1608,11 +1608,18 @@
             match param.kind {
                 ast::GenericParamKind::Lifetime => {
                     let lt = ast::Lifetime { id: param.id, ident: param.ident };
-                    s.print_lifetime_bounds(lt, &param.bounds)
+                    s.print_lifetime(lt);
+                    if !param.bounds.is_empty() {
+                        s.word_nbsp(":");
+                        s.print_lifetime_bounds(&param.bounds)
+                    }
                 }
                 ast::GenericParamKind::Type { ref default } => {
                     s.print_ident(param.ident);
-                    s.print_type_bounds(":", &param.bounds);
+                    if !param.bounds.is_empty() {
+                        s.word_nbsp(":");
+                        s.print_type_bounds(&param.bounds);
+                    }
                     if let Some(ref default) = default {
                         s.space();
                         s.word_space("=");
@@ -1625,7 +1632,10 @@
                     s.space();
                     s.word_space(":");
                     s.print_type(ty);
-                    s.print_type_bounds(":", &param.bounds);
+                    if !param.bounds.is_empty() {
+                        s.word_nbsp(":");
+                        s.print_type_bounds(&param.bounds);
+                    }
                     if let Some(ref default) = default {
                         s.space();
                         s.word_space("=");
@@ -1649,12 +1659,12 @@
         }
     }
 
-    crate fn print_mt(&mut self, mt: &ast::MutTy, print_const: bool) {
+    pub(crate) fn print_mt(&mut self, mt: &ast::MutTy, print_const: bool) {
         self.print_mutability(mt.mutbl, print_const);
         self.print_type(&mt.ty)
     }
 
-    crate fn print_param(&mut self, input: &ast::Param, is_closure: bool) {
+    pub(crate) fn print_param(&mut self, input: &ast::Param, is_closure: bool) {
         self.ibox(INDENT_UNIT);
 
         self.print_outer_attributes_inline(&input.attrs);
@@ -1682,7 +1692,7 @@
         self.end();
     }
 
-    crate fn print_fn_ret_ty(&mut self, fn_ret_ty: &ast::FnRetTy) {
+    pub(crate) fn print_fn_ret_ty(&mut self, fn_ret_ty: &ast::FnRetTy) {
         if let ast::FnRetTy::Ty(ty) = fn_ret_ty {
             self.space_if_not_bol();
             self.ibox(INDENT_UNIT);
@@ -1693,7 +1703,7 @@
         }
     }
 
-    crate fn print_ty_fn(
+    pub(crate) fn print_ty_fn(
         &mut self,
         ext: ast::Extern,
         unsafety: ast::Unsafe,
@@ -1717,7 +1727,7 @@
         self.end();
     }
 
-    crate fn print_fn_header_info(&mut self, header: ast::FnHeader) {
+    pub(crate) fn print_fn_header_info(&mut self, header: ast::FnHeader) {
         self.print_constness(header.constness);
         self.print_asyncness(header.asyncness);
         self.print_unsafety(header.unsafety);
@@ -1737,21 +1747,21 @@
         self.word("fn")
     }
 
-    crate fn print_unsafety(&mut self, s: ast::Unsafe) {
+    pub(crate) fn print_unsafety(&mut self, s: ast::Unsafe) {
         match s {
             ast::Unsafe::No => {}
             ast::Unsafe::Yes(_) => self.word_nbsp("unsafe"),
         }
     }
 
-    crate fn print_constness(&mut self, s: ast::Const) {
+    pub(crate) fn print_constness(&mut self, s: ast::Const) {
         match s {
             ast::Const::No => {}
             ast::Const::Yes(_) => self.word_nbsp("const"),
         }
     }
 
-    crate fn print_is_auto(&mut self, s: ast::IsAuto) {
+    pub(crate) fn print_is_auto(&mut self, s: ast::IsAuto) {
         match s {
             ast::IsAuto::Yes => self.word_nbsp("auto"),
             ast::IsAuto::No => {}
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs
index 23c5a92..f1caf22 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs
@@ -19,7 +19,7 @@
         }
     }
 
-    crate fn print_foreign_item(&mut self, item: &ast::ForeignItem) {
+    pub(crate) fn print_foreign_item(&mut self, item: &ast::ForeignItem) {
         let ast::Item { id, span, ident, ref attrs, ref kind, ref vis, tokens: _ } = *item;
         self.ann.pre(self, AnnNode::SubItem(id));
         self.hardbreak_if_not_bol();
@@ -114,7 +114,10 @@
         self.word_space("type");
         self.print_ident(ident);
         self.print_generic_params(&generics.params);
-        self.print_type_bounds(":", bounds);
+        if !bounds.is_empty() {
+            self.word_nbsp(":");
+            self.print_type_bounds(bounds);
+        }
         self.print_where_clause_parts(where_clauses.0.0, before_predicates);
         if let Some(ty) = ty {
             self.space();
@@ -128,7 +131,7 @@
     }
 
     /// Pretty-prints an item.
-    crate fn print_item(&mut self, item: &ast::Item) {
+    pub(crate) fn print_item(&mut self, item: &ast::Item) {
         self.hardbreak_if_not_bol();
         self.maybe_print_comment(item.span.lo());
         self.print_outer_attributes(&item.attrs);
@@ -320,7 +323,10 @@
                         real_bounds.push(b.clone());
                     }
                 }
-                self.print_type_bounds(":", &real_bounds);
+                if !real_bounds.is_empty() {
+                    self.word_nbsp(":");
+                    self.print_type_bounds(&real_bounds);
+                }
                 self.print_where_clause(&generics.where_clause);
                 self.word(" ");
                 self.bopen();
@@ -347,7 +353,10 @@
                     }
                 }
                 self.nbsp();
-                self.print_type_bounds("=", &real_bounds);
+                if !real_bounds.is_empty() {
+                    self.word_nbsp("=");
+                    self.print_type_bounds(&real_bounds);
+                }
                 self.print_where_clause(&generics.where_clause);
                 self.word(";");
                 self.end(); // end inner head-block
@@ -400,16 +409,12 @@
         self.bclose(span, empty)
     }
 
-    crate fn print_visibility(&mut self, vis: &ast::Visibility) {
+    pub(crate) fn print_visibility(&mut self, vis: &ast::Visibility) {
         match vis.kind {
             ast::VisibilityKind::Public => self.word_nbsp("pub"),
-            ast::VisibilityKind::Crate(sugar) => match sugar {
-                ast::CrateSugar::PubCrate => self.word_nbsp("pub(crate)"),
-                ast::CrateSugar::JustCrate => self.word_nbsp("crate"),
-            },
             ast::VisibilityKind::Restricted { ref path, .. } => {
                 let path = Self::to_string(|s| s.print_path(path, false, 0));
-                if path == "self" || path == "super" {
+                if path == "crate" || path == "self" || path == "super" {
                     self.word_nbsp(format!("pub({})", path))
                 } else {
                     self.word_nbsp(format!("pub(in {})", path))
@@ -484,7 +489,7 @@
         }
     }
 
-    crate fn print_variant(&mut self, v: &ast::Variant) {
+    pub(crate) fn print_variant(&mut self, v: &ast::Variant) {
         self.head("");
         self.print_visibility(&v.vis);
         let generics = ast::Generics::default();
@@ -496,7 +501,7 @@
         }
     }
 
-    crate fn print_assoc_item(&mut self, item: &ast::AssocItem) {
+    pub(crate) fn print_assoc_item(&mut self, item: &ast::AssocItem) {
         let ast::Item { id, span, ident, ref attrs, ref kind, ref vis, tokens: _ } = *item;
         self.ann.pre(self, AnnNode::SubItem(id));
         self.hardbreak_if_not_bol();
@@ -562,7 +567,7 @@
         }
     }
 
-    crate fn print_fn(
+    pub(crate) fn print_fn(
         &mut self,
         decl: &ast::FnDecl,
         header: ast::FnHeader,
@@ -579,7 +584,7 @@
         self.print_where_clause(&generics.where_clause)
     }
 
-    crate fn print_fn_params_and_ret(&mut self, decl: &ast::FnDecl, is_closure: bool) {
+    pub(crate) fn print_fn_params_and_ret(&mut self, decl: &ast::FnDecl, is_closure: bool) {
         let (open, close) = if is_closure { ("|", "|") } else { ("(", ")") };
         self.word(open);
         self.commasep(Inconsistent, &decl.inputs, |s, param| s.print_param(param, is_closure));
@@ -591,7 +596,7 @@
         self.print_where_clause_parts(where_clause.has_where_token, &where_clause.predicates);
     }
 
-    crate fn print_where_clause_parts(
+    pub(crate) fn print_where_clause_parts(
         &mut self,
         has_where_token: bool,
         predicates: &[ast::WherePredicate],
@@ -622,14 +627,23 @@
             }) => {
                 self.print_formal_generic_params(bound_generic_params);
                 self.print_type(bounded_ty);
-                self.print_type_bounds(":", bounds);
+                self.word(":");
+                if !bounds.is_empty() {
+                    self.nbsp();
+                    self.print_type_bounds(bounds);
+                }
             }
             ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate {
                 lifetime,
                 bounds,
                 ..
             }) => {
-                self.print_lifetime_bounds(*lifetime, bounds);
+                self.print_lifetime(*lifetime);
+                self.word(":");
+                if !bounds.is_empty() {
+                    self.nbsp();
+                    self.print_lifetime_bounds(bounds);
+                }
             }
             ast::WherePredicate::EqPredicate(ast::WhereEqPredicate { lhs_ty, rhs_ty, .. }) => {
                 self.print_type(lhs_ty);
diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs
index 3d4bd22..ce7c0eb 100644
--- a/compiler/rustc_attr/src/builtin.rs
+++ b/compiler/rustc_attr/src/builtin.rs
@@ -59,7 +59,7 @@
                     err.span_suggestion(
                         span,
                         "consider removing the prefix",
-                        lint_str[1..].to_string(),
+                        &lint_str[1..],
                         Applicability::MaybeIncorrect,
                     );
                 }
@@ -101,6 +101,16 @@
     pub feature: Symbol,
 }
 
+impl Stability {
+    pub fn is_unstable(&self) -> bool {
+        self.level.is_unstable()
+    }
+
+    pub fn is_stable(&self) -> bool {
+        self.level.is_stable()
+    }
+}
+
 /// Represents the `#[rustc_const_unstable]` and `#[rustc_const_stable]` attributes.
 #[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, Hash)]
 #[derive(HashStable_Generic)]
@@ -111,6 +121,16 @@
     pub promotable: bool,
 }
 
+impl ConstStability {
+    pub fn is_const_unstable(&self) -> bool {
+        self.level.is_unstable()
+    }
+
+    pub fn is_const_stable(&self) -> bool {
+        self.level.is_stable()
+    }
+}
+
 /// The available stability levels.
 #[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, Hash)]
 #[derive(HashStable_Generic)]
@@ -434,6 +454,15 @@
     sess.first_attr_value_str_by_name(attrs, sym::crate_name)
 }
 
+#[derive(Clone, Debug)]
+pub struct Condition {
+    pub name: Symbol,
+    pub name_span: Span,
+    pub value: Option<Symbol>,
+    pub value_span: Option<Span>,
+    pub span: Span,
+}
+
 /// Tests if a cfg-pattern matches the cfg set
 pub fn cfg_matches(
     cfg: &ast::MetaItem,
@@ -442,70 +471,42 @@
     features: Option<&Features>,
 ) -> bool {
     eval_condition(cfg, sess, features, &mut |cfg| {
-        try_gate_cfg(cfg, sess, features);
-        let error = |span, msg| {
-            sess.span_diagnostic.span_err(span, msg);
-            true
-        };
-        if cfg.path.segments.len() != 1 {
-            return error(cfg.path.span, "`cfg` predicate key must be an identifier");
-        }
-        match &cfg.kind {
-            MetaItemKind::List(..) => {
-                error(cfg.span, "unexpected parentheses after `cfg` predicate key")
-            }
-            MetaItemKind::NameValue(lit) if !lit.kind.is_str() => {
-                handle_errors(
-                    sess,
-                    lit.span,
-                    AttrError::UnsupportedLiteral(
-                        "literal in `cfg` predicate value must be a string",
-                        lit.kind.is_bytestr(),
-                    ),
+        try_gate_cfg(cfg.name, cfg.span, sess, features);
+        if let Some(names_valid) = &sess.check_config.names_valid {
+            if !names_valid.contains(&cfg.name) {
+                sess.buffer_lint_with_diagnostic(
+                    UNEXPECTED_CFGS,
+                    cfg.span,
+                    lint_node_id,
+                    "unexpected `cfg` condition name",
+                    BuiltinLintDiagnostics::UnexpectedCfg((cfg.name, cfg.name_span), None),
                 );
-                true
-            }
-            MetaItemKind::NameValue(..) | MetaItemKind::Word => {
-                let ident = cfg.ident().expect("multi-segment cfg predicate");
-                let name = ident.name;
-                let value = cfg.value_str();
-                if let Some(names_valid) = &sess.check_config.names_valid {
-                    if !names_valid.contains(&name) {
-                        sess.buffer_lint_with_diagnostic(
-                            UNEXPECTED_CFGS,
-                            cfg.span,
-                            lint_node_id,
-                            "unexpected `cfg` condition name",
-                            BuiltinLintDiagnostics::UnexpectedCfg((name, ident.span), None),
-                        );
-                    }
-                }
-                if let Some(value) = value {
-                    if let Some(values) = &sess.check_config.values_valid.get(&name) {
-                        if !values.contains(&value) {
-                            sess.buffer_lint_with_diagnostic(
-                                UNEXPECTED_CFGS,
-                                cfg.span,
-                                lint_node_id,
-                                "unexpected `cfg` condition value",
-                                BuiltinLintDiagnostics::UnexpectedCfg(
-                                    (name, ident.span),
-                                    Some((value, cfg.name_value_literal_span().unwrap())),
-                                ),
-                            );
-                        }
-                    }
-                }
-                sess.config.contains(&(name, value))
             }
         }
+        if let Some(value) = cfg.value {
+            if let Some(values) = &sess.check_config.values_valid.get(&cfg.name) {
+                if !values.contains(&value) {
+                    sess.buffer_lint_with_diagnostic(
+                        UNEXPECTED_CFGS,
+                        cfg.span,
+                        lint_node_id,
+                        "unexpected `cfg` condition value",
+                        BuiltinLintDiagnostics::UnexpectedCfg(
+                            (cfg.name, cfg.name_span),
+                            cfg.value_span.map(|vs| (value, vs)),
+                        ),
+                    );
+                }
+            }
+        }
+        sess.config.contains(&(cfg.name, cfg.value))
     })
 }
 
-fn try_gate_cfg(cfg: &ast::MetaItem, sess: &ParseSess, features: Option<&Features>) {
-    let gate = find_gated_cfg(|sym| cfg.has_name(sym));
+fn try_gate_cfg(name: Symbol, span: Span, sess: &ParseSess, features: Option<&Features>) {
+    let gate = find_gated_cfg(|sym| sym == name);
     if let (Some(feats), Some(gated_cfg)) = (features, gate) {
-        gate_cfg(&gated_cfg, cfg.span, sess, feats);
+        gate_cfg(&gated_cfg, span, sess, feats);
     }
 }
 
@@ -543,11 +544,11 @@
     cfg: &ast::MetaItem,
     sess: &ParseSess,
     features: Option<&Features>,
-    eval: &mut impl FnMut(&ast::MetaItem) -> bool,
+    eval: &mut impl FnMut(Condition) -> bool,
 ) -> bool {
     match cfg.kind {
         ast::MetaItemKind::List(ref mis) if cfg.name_or_empty() == sym::version => {
-            try_gate_cfg(cfg, sess, features);
+            try_gate_cfg(sym::version, cfg.span, sess, features);
             let (min_version, span) = match &mis[..] {
                 [NestedMetaItem::Literal(Lit { kind: LitKind::Str(sym, ..), span, .. })] => {
                     (sym, span)
@@ -629,6 +630,25 @@
 
                     !eval_condition(mis[0].meta_item().unwrap(), sess, features, eval)
                 }
+                sym::target => {
+                    if let Some(features) = features && !features.cfg_target_compact {
+                        feature_err(
+                            sess,
+                            sym::cfg_target_compact,
+                            cfg.span,
+                            &"compact `cfg(target(..))` is experimental and subject to change"
+                        ).emit();
+                    }
+
+                    mis.iter().fold(true, |res, mi| {
+                        let mut mi = mi.meta_item().unwrap().clone();
+                        if let [seg, ..] = &mut mi.path.segments[..] {
+                            seg.ident.name = Symbol::intern(&format!("target_{}", seg.ident.name));
+                        }
+
+                        res & eval_condition(&mi, sess, features, eval)
+                    })
+                }
                 _ => {
                     struct_span_err!(
                         sess.span_diagnostic,
@@ -642,7 +662,32 @@
                 }
             }
         }
-        ast::MetaItemKind::Word | ast::MetaItemKind::NameValue(..) => eval(cfg),
+        ast::MetaItemKind::Word | MetaItemKind::NameValue(..) if cfg.path.segments.len() != 1 => {
+            sess.span_diagnostic
+                .span_err(cfg.path.span, "`cfg` predicate key must be an identifier");
+            true
+        }
+        MetaItemKind::NameValue(ref lit) if !lit.kind.is_str() => {
+            handle_errors(
+                sess,
+                lit.span,
+                AttrError::UnsupportedLiteral(
+                    "literal in `cfg` predicate value must be a string",
+                    lit.kind.is_bytestr(),
+                ),
+            );
+            true
+        }
+        ast::MetaItemKind::Word | ast::MetaItemKind::NameValue(..) => {
+            let ident = cfg.ident().expect("multi-segment cfg predicate");
+            eval(Condition {
+                name: ident.name,
+                name_span: ident.span,
+                value: cfg.value_str(),
+                value_span: cfg.name_value_literal_span(),
+                span: cfg.span,
+            })
+        }
     }
 }
 
@@ -675,18 +720,10 @@
     let is_rustc = sess.features_untracked().staged_api;
 
     'outer: for attr in attrs_iter {
-        if !(attr.has_name(sym::deprecated) || attr.has_name(sym::rustc_deprecated)) {
+        if !attr.has_name(sym::deprecated) {
             continue;
         }
 
-        // FIXME(jhpratt) remove this eventually
-        if attr.has_name(sym::rustc_deprecated) {
-            diagnostic
-                .struct_span_err(attr.span, "`#[rustc_deprecated]` has been removed")
-                .help("use `#[deprecated]` instead")
-                .emit();
-        }
-
         let Some(meta) = attr.meta() else {
             continue;
         };
@@ -742,25 +779,6 @@
                                     continue 'outer;
                                 }
                             }
-                            // FIXME(jhpratt) remove this eventually
-                            sym::reason if attr.has_name(sym::rustc_deprecated) => {
-                                if !get(mi, &mut note) {
-                                    continue 'outer;
-                                }
-
-                                let mut diag = diagnostic
-                                    .struct_span_err(mi.span, "`reason` has been renamed");
-                                match note {
-                                    Some(note) => diag.span_suggestion(
-                                        mi.span,
-                                        "use `note` instead",
-                                        format!("note = \"{note}\""),
-                                        Applicability::MachineApplicable,
-                                    ),
-                                    None => diag.span_help(mi.span, "use `note` instead"),
-                                };
-                                diag.emit();
-                            }
                             sym::suggestion => {
                                 if !sess.features_untracked().deprecated_suggestion {
                                     let mut diag = sess.struct_span_err(
@@ -897,7 +915,7 @@
                         err.span_suggestion(
                             item.span(),
                             "supply an argument here",
-                            "align(...)".to_string(),
+                            "align(...)",
                             Applicability::HasPlaceholders,
                         );
                         err.emit();
diff --git a/compiler/rustc_attr/src/lib.rs b/compiler/rustc_attr/src/lib.rs
index c95c1c4..c3f9f0c 100644
--- a/compiler/rustc_attr/src/lib.rs
+++ b/compiler/rustc_attr/src/lib.rs
@@ -4,6 +4,7 @@
 //! The goal is to move the definition of `MetaItem` and things that don't need to be in `syntax`
 //! to this crate.
 
+#![feature(let_chains)]
 #![feature(let_else)]
 
 #[macro_use]
diff --git a/compiler/rustc_borrowck/src/borrow_set.rs b/compiler/rustc_borrowck/src/borrow_set.rs
index 7c921b8..c7d0e33 100644
--- a/compiler/rustc_borrowck/src/borrow_set.rs
+++ b/compiler/rustc_borrowck/src/borrow_set.rs
@@ -29,7 +29,7 @@
     /// Map from local to all the borrows on that local.
     pub local_map: FxHashMap<mir::Local, FxHashSet<BorrowIndex>>,
 
-    crate locals_state_at_exit: LocalsStateAtExit,
+    pub(crate) locals_state_at_exit: LocalsStateAtExit,
 }
 
 impl<'tcx> Index<BorrowIndex> for BorrowSet<'tcx> {
@@ -148,23 +148,23 @@
         }
     }
 
-    crate fn activations_at_location(&self, location: Location) -> &[BorrowIndex] {
+    pub(crate) fn activations_at_location(&self, location: Location) -> &[BorrowIndex] {
         self.activation_map.get(&location).map_or(&[], |activations| &activations[..])
     }
 
-    crate fn len(&self) -> usize {
+    pub(crate) fn len(&self) -> usize {
         self.location_map.len()
     }
 
-    crate fn indices(&self) -> impl Iterator<Item = BorrowIndex> {
+    pub(crate) fn indices(&self) -> impl Iterator<Item = BorrowIndex> {
         BorrowIndex::from_usize(0)..BorrowIndex::from_usize(self.len())
     }
 
-    crate fn iter_enumerated(&self) -> impl Iterator<Item = (BorrowIndex, &BorrowData<'tcx>)> {
+    pub(crate) fn iter_enumerated(&self) -> impl Iterator<Item = (BorrowIndex, &BorrowData<'tcx>)> {
         self.indices().zip(self.location_map.values())
     }
 
-    crate fn get_index_of(&self, location: &Location) -> Option<BorrowIndex> {
+    pub(crate) fn get_index_of(&self, location: &Location) -> Option<BorrowIndex> {
         self.location_map.get_index_of(location).map(BorrowIndex::from)
     }
 }
diff --git a/compiler/rustc_borrowck/src/borrowck_errors.rs b/compiler/rustc_borrowck/src/borrowck_errors.rs
index 70f7f1e..a1233d6 100644
--- a/compiler/rustc_borrowck/src/borrowck_errors.rs
+++ b/compiler/rustc_borrowck/src/borrowck_errors.rs
@@ -3,7 +3,7 @@
 use rustc_span::Span;
 
 impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
-    crate fn cannot_move_when_borrowed(
+    pub(crate) fn cannot_move_when_borrowed(
         &self,
         span: Span,
         desc: &str,
@@ -11,7 +11,7 @@
         struct_span_err!(self, span, E0505, "cannot move out of {} because it is borrowed", desc,)
     }
 
-    crate fn cannot_use_when_mutably_borrowed(
+    pub(crate) fn cannot_use_when_mutably_borrowed(
         &self,
         span: Span,
         desc: &str,
@@ -31,7 +31,7 @@
         err
     }
 
-    crate fn cannot_act_on_uninitialized_variable(
+    pub(crate) fn cannot_act_on_uninitialized_variable(
         &self,
         span: Span,
         verb: &str,
@@ -47,7 +47,7 @@
         )
     }
 
-    crate fn cannot_mutably_borrow_multiply(
+    pub(crate) fn cannot_mutably_borrow_multiply(
         &self,
         new_loan_span: Span,
         desc: &str,
@@ -97,7 +97,7 @@
         err
     }
 
-    crate fn cannot_uniquely_borrow_by_two_closures(
+    pub(crate) fn cannot_uniquely_borrow_by_two_closures(
         &self,
         new_loan_span: Span,
         desc: &str,
@@ -126,7 +126,7 @@
         err
     }
 
-    crate fn cannot_uniquely_borrow_by_one_closure(
+    pub(crate) fn cannot_uniquely_borrow_by_one_closure(
         &self,
         new_loan_span: Span,
         container_name: &str,
@@ -157,7 +157,7 @@
         err
     }
 
-    crate fn cannot_reborrow_already_uniquely_borrowed(
+    pub(crate) fn cannot_reborrow_already_uniquely_borrowed(
         &self,
         new_loan_span: Span,
         container_name: &str,
@@ -193,7 +193,7 @@
         err
     }
 
-    crate fn cannot_reborrow_already_borrowed(
+    pub(crate) fn cannot_reborrow_already_borrowed(
         &self,
         span: Span,
         desc_new: &str,
@@ -242,7 +242,7 @@
         err
     }
 
-    crate fn cannot_assign_to_borrowed(
+    pub(crate) fn cannot_assign_to_borrowed(
         &self,
         span: Span,
         borrow_span: Span,
@@ -261,7 +261,7 @@
         err
     }
 
-    crate fn cannot_reassign_immutable(
+    pub(crate) fn cannot_reassign_immutable(
         &self,
         span: Span,
         desc: &str,
@@ -271,7 +271,7 @@
         struct_span_err!(self, span, E0384, "cannot assign {} {}", msg, desc)
     }
 
-    crate fn cannot_assign(
+    pub(crate) fn cannot_assign(
         &self,
         span: Span,
         desc: &str,
@@ -279,7 +279,7 @@
         struct_span_err!(self, span, E0594, "cannot assign to {}", desc)
     }
 
-    crate fn cannot_move_out_of(
+    pub(crate) fn cannot_move_out_of(
         &self,
         move_from_span: Span,
         move_from_desc: &str,
@@ -290,7 +290,7 @@
     /// Signal an error due to an attempt to move out of the interior
     /// of an array or slice. `is_index` is None when error origin
     /// didn't capture whether there was an indexing operation or not.
-    crate fn cannot_move_out_of_interior_noncopy(
+    pub(crate) fn cannot_move_out_of_interior_noncopy(
         &self,
         move_from_span: Span,
         ty: Ty<'_>,
@@ -313,7 +313,7 @@
         err
     }
 
-    crate fn cannot_move_out_of_interior_of_drop(
+    pub(crate) fn cannot_move_out_of_interior_of_drop(
         &self,
         move_from_span: Span,
         container_ty: Ty<'_>,
@@ -329,7 +329,7 @@
         err
     }
 
-    crate fn cannot_act_on_moved_value(
+    pub(crate) fn cannot_act_on_moved_value(
         &self,
         use_span: Span,
         verb: &str,
@@ -349,7 +349,7 @@
         )
     }
 
-    crate fn cannot_borrow_path_as_mutable_because(
+    pub(crate) fn cannot_borrow_path_as_mutable_because(
         &self,
         span: Span,
         path: &str,
@@ -358,7 +358,7 @@
         struct_span_err!(self, span, E0596, "cannot borrow {} as mutable{}", path, reason,)
     }
 
-    crate fn cannot_mutate_in_immutable_section(
+    pub(crate) fn cannot_mutate_in_immutable_section(
         &self,
         mutate_span: Span,
         immutable_span: Span,
@@ -380,7 +380,7 @@
         err
     }
 
-    crate fn cannot_borrow_across_generator_yield(
+    pub(crate) fn cannot_borrow_across_generator_yield(
         &self,
         span: Span,
         yield_span: Span,
@@ -395,7 +395,7 @@
         err
     }
 
-    crate fn cannot_borrow_across_destructor(
+    pub(crate) fn cannot_borrow_across_destructor(
         &self,
         borrow_span: Span,
     ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
@@ -407,7 +407,7 @@
         )
     }
 
-    crate fn path_does_not_live_long_enough(
+    pub(crate) fn path_does_not_live_long_enough(
         &self,
         span: Span,
         path: &str,
@@ -415,7 +415,7 @@
         struct_span_err!(self, span, E0597, "{} does not live long enough", path,)
     }
 
-    crate fn cannot_return_reference_to_local(
+    pub(crate) fn cannot_return_reference_to_local(
         &self,
         span: Span,
         return_kind: &str,
@@ -440,7 +440,7 @@
         err
     }
 
-    crate fn cannot_capture_in_long_lived_closure(
+    pub(crate) fn cannot_capture_in_long_lived_closure(
         &self,
         closure_span: Span,
         closure_kind: &str,
@@ -462,14 +462,14 @@
         err
     }
 
-    crate fn thread_local_value_does_not_live_long_enough(
+    pub(crate) fn thread_local_value_does_not_live_long_enough(
         &self,
         span: Span,
     ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
         struct_span_err!(self, span, E0712, "thread-local variable borrowed past end of function",)
     }
 
-    crate fn temporary_value_borrowed_for_too_long(
+    pub(crate) fn temporary_value_borrowed_for_too_long(
         &self,
         span: Span,
     ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
@@ -486,7 +486,7 @@
     }
 }
 
-crate fn borrowed_data_escapes_closure<'tcx>(
+pub(crate) fn borrowed_data_escapes_closure<'tcx>(
     tcx: TyCtxt<'tcx>,
     escape_span: Span,
     escapes_from: &str,
diff --git a/compiler/rustc_borrowck/src/constraint_generation.rs b/compiler/rustc_borrowck/src/constraint_generation.rs
index 22edee3..e4ffae3 100644
--- a/compiler/rustc_borrowck/src/constraint_generation.rs
+++ b/compiler/rustc_borrowck/src/constraint_generation.rs
@@ -140,9 +140,7 @@
         // A `Call` terminator's return value can be a local which has borrows,
         // so we need to record those as `killed` as well.
         if let TerminatorKind::Call { destination, .. } = terminator.kind {
-            if let Some((place, _)) = destination {
-                self.record_killed_borrows_for_place(place, location);
-            }
+            self.record_killed_borrows_for_place(destination, location);
         }
 
         self.super_terminator(terminator, location);
diff --git a/compiler/rustc_borrowck/src/constraints/graph.rs b/compiler/rustc_borrowck/src/constraints/graph.rs
index c19a39c..609fbc2 100644
--- a/compiler/rustc_borrowck/src/constraints/graph.rs
+++ b/compiler/rustc_borrowck/src/constraints/graph.rs
@@ -13,19 +13,19 @@
 /// The construct graph organizes the constraints by their end-points.
 /// It can be used to view a `R1: R2` constraint as either an edge `R1
 /// -> R2` or `R2 -> R1` depending on the direction type `D`.
-crate struct ConstraintGraph<D: ConstraintGraphDirecton> {
+pub(crate) struct ConstraintGraph<D: ConstraintGraphDirecton> {
     _direction: D,
     first_constraints: IndexVec<RegionVid, Option<OutlivesConstraintIndex>>,
     next_constraints: IndexVec<OutlivesConstraintIndex, Option<OutlivesConstraintIndex>>,
 }
 
-crate type NormalConstraintGraph = ConstraintGraph<Normal>;
+pub(crate) type NormalConstraintGraph = ConstraintGraph<Normal>;
 
-crate type ReverseConstraintGraph = ConstraintGraph<Reverse>;
+pub(crate) type ReverseConstraintGraph = ConstraintGraph<Reverse>;
 
 /// Marker trait that controls whether a `R1: R2` constraint
 /// represents an edge `R1 -> R2` or `R2 -> R1`.
-crate trait ConstraintGraphDirecton: Copy + 'static {
+pub(crate) trait ConstraintGraphDirecton: Copy + 'static {
     fn start_region(c: &OutlivesConstraint<'_>) -> RegionVid;
     fn end_region(c: &OutlivesConstraint<'_>) -> RegionVid;
     fn is_normal() -> bool;
@@ -36,7 +36,7 @@
 /// inference. This is because we compute the value of R1 by union'ing
 /// all the things that it relies on.
 #[derive(Copy, Clone, Debug)]
-crate struct Normal;
+pub(crate) struct Normal;
 
 impl ConstraintGraphDirecton for Normal {
     fn start_region(c: &OutlivesConstraint<'_>) -> RegionVid {
@@ -57,7 +57,7 @@
 /// we wish to iterate from a region (e.g., R2) to all the regions
 /// that will outlive it (e.g., R1).
 #[derive(Copy, Clone, Debug)]
-crate struct Reverse;
+pub(crate) struct Reverse;
 
 impl ConstraintGraphDirecton for Reverse {
     fn start_region(c: &OutlivesConstraint<'_>) -> RegionVid {
@@ -78,7 +78,11 @@
     /// R2` is treated as an edge `R1 -> R2`. We use this graph to
     /// construct SCCs for region inference but also for error
     /// reporting.
-    crate fn new(direction: D, set: &OutlivesConstraintSet<'_>, num_region_vars: usize) -> Self {
+    pub(crate) fn new(
+        direction: D,
+        set: &OutlivesConstraintSet<'_>,
+        num_region_vars: usize,
+    ) -> Self {
         let mut first_constraints = IndexVec::from_elem_n(None, num_region_vars);
         let mut next_constraints = IndexVec::from_elem(None, &set.outlives);
 
@@ -96,7 +100,7 @@
     /// Given the constraint set from which this graph was built
     /// creates a region graph so that you can iterate over *regions*
     /// and not constraints.
-    crate fn region_graph<'rg, 'tcx>(
+    pub(crate) fn region_graph<'rg, 'tcx>(
         &'rg self,
         set: &'rg OutlivesConstraintSet<'tcx>,
         static_region: RegionVid,
@@ -105,7 +109,7 @@
     }
 
     /// Given a region `R`, iterate over all constraints `R: R1`.
-    crate fn outgoing_edges<'a, 'tcx>(
+    pub(crate) fn outgoing_edges<'a, 'tcx>(
         &'a self,
         region_sup: RegionVid,
         constraints: &'a OutlivesConstraintSet<'tcx>,
@@ -129,7 +133,7 @@
     }
 }
 
-crate struct Edges<'s, 'tcx, D: ConstraintGraphDirecton> {
+pub(crate) struct Edges<'s, 'tcx, D: ConstraintGraphDirecton> {
     graph: &'s ConstraintGraph<D>,
     constraints: &'s OutlivesConstraintSet<'tcx>,
     pointer: Option<OutlivesConstraintIndex>,
@@ -169,7 +173,7 @@
 /// This struct brings together a constraint set and a (normal, not
 /// reverse) constraint graph. It implements the graph traits and is
 /// usd for doing the SCC computation.
-crate struct RegionGraph<'s, 'tcx, D: ConstraintGraphDirecton> {
+pub(crate) struct RegionGraph<'s, 'tcx, D: ConstraintGraphDirecton> {
     set: &'s OutlivesConstraintSet<'tcx>,
     constraint_graph: &'s ConstraintGraph<D>,
     static_region: RegionVid,
@@ -180,7 +184,7 @@
     /// R2` is treated as an edge `R1 -> R2`. We use this graph to
     /// construct SCCs for region inference but also for error
     /// reporting.
-    crate fn new(
+    pub(crate) fn new(
         set: &'s OutlivesConstraintSet<'tcx>,
         constraint_graph: &'s ConstraintGraph<D>,
         static_region: RegionVid,
@@ -190,14 +194,14 @@
 
     /// Given a region `R`, iterate over all regions `R1` such that
     /// there exists a constraint `R: R1`.
-    crate fn outgoing_regions(&self, region_sup: RegionVid) -> Successors<'s, 'tcx, D> {
+    pub(crate) fn outgoing_regions(&self, region_sup: RegionVid) -> Successors<'s, 'tcx, D> {
         Successors {
             edges: self.constraint_graph.outgoing_edges(region_sup, self.set, self.static_region),
         }
     }
 }
 
-crate struct Successors<'s, 'tcx, D: ConstraintGraphDirecton> {
+pub(crate) struct Successors<'s, 'tcx, D: ConstraintGraphDirecton> {
     edges: Edges<'s, 'tcx, D>,
 }
 
diff --git a/compiler/rustc_borrowck/src/constraints/mod.rs b/compiler/rustc_borrowck/src/constraints/mod.rs
index 14f0e5f..a504d0c 100644
--- a/compiler/rustc_borrowck/src/constraints/mod.rs
+++ b/compiler/rustc_borrowck/src/constraints/mod.rs
@@ -8,19 +8,19 @@
 
 use crate::type_check::Locations;
 
-crate mod graph;
+pub(crate) mod graph;
 
 /// A set of NLL region constraints. These include "outlives"
 /// constraints of the form `R1: R2`. Each constraint is identified by
 /// a unique `OutlivesConstraintIndex` and you can index into the set
 /// (`constraint_set[i]`) to access the constraint details.
 #[derive(Clone, Default)]
-crate struct OutlivesConstraintSet<'tcx> {
+pub(crate) struct OutlivesConstraintSet<'tcx> {
     outlives: IndexVec<OutlivesConstraintIndex, OutlivesConstraint<'tcx>>,
 }
 
 impl<'tcx> OutlivesConstraintSet<'tcx> {
-    crate fn push(&mut self, constraint: OutlivesConstraint<'tcx>) {
+    pub(crate) fn push(&mut self, constraint: OutlivesConstraint<'tcx>) {
         debug!(
             "OutlivesConstraintSet::push({:?}: {:?} @ {:?}",
             constraint.sup, constraint.sub, constraint.locations
@@ -38,20 +38,20 @@
     /// N.B., this graph contains a "frozen" view of the current
     /// constraints. Any new constraints added to the `OutlivesConstraintSet`
     /// after the graph is built will not be present in the graph.
-    crate fn graph(&self, num_region_vars: usize) -> graph::NormalConstraintGraph {
+    pub(crate) fn graph(&self, num_region_vars: usize) -> graph::NormalConstraintGraph {
         graph::ConstraintGraph::new(graph::Normal, self, num_region_vars)
     }
 
     /// Like `graph`, but constraints a reverse graph where `R1: R2`
     /// represents an edge `R2 -> R1`.
-    crate fn reverse_graph(&self, num_region_vars: usize) -> graph::ReverseConstraintGraph {
+    pub(crate) fn reverse_graph(&self, num_region_vars: usize) -> graph::ReverseConstraintGraph {
         graph::ConstraintGraph::new(graph::Reverse, self, num_region_vars)
     }
 
     /// Computes cycles (SCCs) in the graph of regions. In particular,
     /// find all regions R1, R2 such that R1: R2 and R2: R1 and group
     /// them into an SCC, and find the relationships between SCCs.
-    crate fn compute_sccs(
+    pub(crate) fn compute_sccs(
         &self,
         constraint_graph: &graph::NormalConstraintGraph,
         static_region: RegionVid,
@@ -60,7 +60,7 @@
         Sccs::new(region_graph)
     }
 
-    crate fn outlives(&self) -> &IndexVec<OutlivesConstraintIndex, OutlivesConstraint<'tcx>> {
+    pub(crate) fn outlives(&self) -> &IndexVec<OutlivesConstraintIndex, OutlivesConstraint<'tcx>> {
         &self.outlives
     }
 }
@@ -95,7 +95,7 @@
     pub span: Span,
 
     /// What caused this constraint?
-    pub category: ConstraintCategory,
+    pub category: ConstraintCategory<'tcx>,
 
     /// Variance diagnostic information
     pub variance_info: VarianceDiagInfo<'tcx>,
diff --git a/compiler/rustc_borrowck/src/dataflow.rs b/compiler/rustc_borrowck/src/dataflow.rs
index d38e89c..97d5a8d 100644
--- a/compiler/rustc_borrowck/src/dataflow.rs
+++ b/compiler/rustc_borrowck/src/dataflow.rs
@@ -199,7 +199,7 @@
                 // Add successor BBs to the work list, if necessary.
                 let bb_data = &self.body[bb];
                 debug_assert!(hi == bb_data.statements.len());
-                for &succ_bb in bb_data.terminator().successors() {
+                for succ_bb in bb_data.terminator().successors() {
                     if !self.visited.insert(succ_bb) {
                         if succ_bb == location.block && first_lo > 0 {
                             // `succ_bb` has been seen before. If it wasn't
@@ -233,7 +233,7 @@
 }
 
 impl<'a, 'tcx> Borrows<'a, 'tcx> {
-    crate fn new(
+    pub(crate) fn new(
         tcx: TyCtxt<'tcx>,
         body: &'a Body<'tcx>,
         nonlexical_regioncx: &'a RegionInferenceContext<'tcx>,
diff --git a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs
index 8601fbe..07f1821 100644
--- a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs
@@ -22,7 +22,7 @@
 use crate::MirBorrowckCtxt;
 
 #[derive(Clone)]
-crate struct UniverseInfo<'tcx>(UniverseInfoInner<'tcx>);
+pub(crate) struct UniverseInfo<'tcx>(UniverseInfoInner<'tcx>);
 
 /// What operation a universe was created for.
 #[derive(Clone)]
@@ -36,15 +36,15 @@
 }
 
 impl<'tcx> UniverseInfo<'tcx> {
-    crate fn other() -> UniverseInfo<'tcx> {
+    pub(crate) fn other() -> UniverseInfo<'tcx> {
         UniverseInfo(UniverseInfoInner::Other)
     }
 
-    crate fn relate(expected: Ty<'tcx>, found: Ty<'tcx>) -> UniverseInfo<'tcx> {
+    pub(crate) fn relate(expected: Ty<'tcx>, found: Ty<'tcx>) -> UniverseInfo<'tcx> {
         UniverseInfo(UniverseInfoInner::RelateTys { expected, found })
     }
 
-    crate fn report_error(
+    pub(crate) fn report_error(
         &self,
         mbcx: &mut MirBorrowckCtxt<'_, 'tcx>,
         placeholder: ty::PlaceholderRegion,
@@ -76,7 +76,7 @@
     }
 }
 
-crate trait ToUniverseInfo<'tcx> {
+pub(crate) trait ToUniverseInfo<'tcx> {
     fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx>;
 }
 
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index a3c9da3..73c0bf1 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -1,5 +1,6 @@
 use either::Either;
 use rustc_const_eval::util::CallKind;
+use rustc_data_structures::captures::Captures;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan};
 use rustc_hir as hir;
@@ -224,7 +225,7 @@
                                     .map(|n| format!("`{}`", n))
                                     .unwrap_or_else(|| "the value".to_string())
                             ),
-                            "ref ".to_string(),
+                            "ref ",
                             Applicability::MachineApplicable,
                         );
                         in_pattern = true;
@@ -275,7 +276,7 @@
                                 .map(|n| format!("`{}`", n))
                                 .unwrap_or_else(|| "the mutable reference".to_string()),
                         ),
-                        "&mut *".to_string(),
+                        "&mut *",
                         Applicability::MachineApplicable,
                     );
                 }
@@ -787,7 +788,7 @@
         err: &mut Diagnostic,
         location: Location,
         issued_borrow: &BorrowData<'tcx>,
-        explanation: BorrowExplanation,
+        explanation: BorrowExplanation<'tcx>,
     ) {
         let used_in_call = matches!(
             explanation,
@@ -1087,7 +1088,7 @@
                 BorrowExplanation::MustBeValidFor {
                     category:
                         category @ (ConstraintCategory::Return(_)
-                        | ConstraintCategory::CallArgument
+                        | ConstraintCategory::CallArgument(_)
                         | ConstraintCategory::OpaqueType),
                     from_closure: false,
                     ref region_name,
@@ -1146,7 +1147,7 @@
         borrow: &BorrowData<'tcx>,
         drop_span: Span,
         borrow_spans: UseSpans<'tcx>,
-        explanation: BorrowExplanation,
+        explanation: BorrowExplanation<'tcx>,
     ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
         debug!(
             "report_local_value_does_not_live_long_enough(\
@@ -1351,7 +1352,7 @@
         drop_span: Span,
         borrow_spans: UseSpans<'tcx>,
         proper_span: Span,
-        explanation: BorrowExplanation,
+        explanation: BorrowExplanation<'tcx>,
     ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
         debug!(
             "report_temporary_value_does_not_live_long_enough(\
@@ -1409,7 +1410,7 @@
         borrow: &BorrowData<'tcx>,
         borrow_span: Span,
         return_span: Span,
-        category: ConstraintCategory,
+        category: ConstraintCategory<'tcx>,
         opt_place_desc: Option<&String>,
     ) -> Option<DiagnosticBuilder<'cx, ErrorGuaranteed>> {
         let return_kind = match category {
@@ -1507,7 +1508,7 @@
         use_span: UseSpans<'tcx>,
         var_span: Span,
         fr_name: &RegionName,
-        category: ConstraintCategory,
+        category: ConstraintCategory<'tcx>,
         constraint_span: Span,
         captured_var: &str,
     ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
@@ -1518,15 +1519,15 @@
             Ok(string) => {
                 if string.starts_with("async ") {
                     let pos = args_span.lo() + BytePos(6);
-                    (args_span.with_lo(pos).with_hi(pos), "move ".to_string())
+                    (args_span.with_lo(pos).with_hi(pos), "move ")
                 } else if string.starts_with("async|") {
                     let pos = args_span.lo() + BytePos(5);
-                    (args_span.with_lo(pos).with_hi(pos), " move".to_string())
+                    (args_span.with_lo(pos).with_hi(pos), " move")
                 } else {
-                    (args_span.shrink_to_lo(), "move ".to_string())
+                    (args_span.shrink_to_lo(), "move ")
                 }
             }
-            Err(_) => (args_span, "move |<args>| <body>".to_string()),
+            Err(_) => (args_span, "move |<args>| <body>"),
         };
         let kind = match use_span.generator_kind() {
             Some(generator_kind) => match generator_kind {
@@ -1558,7 +1559,7 @@
                 let msg = format!("{} is returned here", kind);
                 err.span_note(constraint_span, &msg);
             }
-            ConstraintCategory::CallArgument => {
+            ConstraintCategory::CallArgument(_) => {
                 fr_name.highlight_region_name(&mut err);
                 if matches!(use_span.generator_kind(), Some(GeneratorKind::Async(_))) {
                     err.note(
@@ -1622,10 +1623,10 @@
         location: Location,
         mpi: MovePathIndex,
     ) -> (Vec<MoveSite>, Vec<Location>) {
-        fn predecessor_locations<'a>(
-            body: &'a mir::Body<'_>,
+        fn predecessor_locations<'tcx, 'a>(
+            body: &'a mir::Body<'tcx>,
             location: Location,
-        ) -> impl Iterator<Item = Location> + 'a {
+        ) -> impl Iterator<Item = Location> + Captures<'tcx> + 'a {
             if location.statement_index == 0 {
                 let predecessors = body.predecessors()[location.block].to_vec();
                 Either::Left(predecessors.into_iter().map(move |bb| body.terminator_loc(bb)))
@@ -2197,10 +2198,10 @@
                 "annotate_argument_and_return_for_borrow: target={:?} terminator={:?}",
                 target, terminator
             );
-            if let TerminatorKind::Call { destination: Some((place, _)), args, .. } =
+            if let TerminatorKind::Call { destination, target: Some(_), args, .. } =
                 &terminator.kind
             {
-                if let Some(assigned_to) = place.as_local() {
+                if let Some(assigned_to) = destination.as_local() {
                     debug!(
                         "annotate_argument_and_return_for_borrow: assigned_to={:?} args={:?}",
                         assigned_to, args
diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
index ffea15b..230ccf5 100644
--- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
@@ -24,7 +24,7 @@
 use super::{find_use, RegionName, UseSpans};
 
 #[derive(Debug)]
-pub(crate) enum BorrowExplanation {
+pub(crate) enum BorrowExplanation<'tcx> {
     UsedLater(LaterUseKind, Span, Option<Span>),
     UsedLaterInLoop(LaterUseKind, Span, Option<Span>),
     UsedLaterWhenDropped {
@@ -33,7 +33,7 @@
         should_note_order: bool,
     },
     MustBeValidFor {
-        category: ConstraintCategory,
+        category: ConstraintCategory<'tcx>,
         from_closure: bool,
         span: Span,
         region_name: RegionName,
@@ -51,11 +51,11 @@
     Other,
 }
 
-impl BorrowExplanation {
+impl<'tcx> BorrowExplanation<'tcx> {
     pub(crate) fn is_explained(&self) -> bool {
         !matches!(self, BorrowExplanation::Unexplained)
     }
-    pub(crate) fn add_explanation_to_diagnostic<'tcx>(
+    pub(crate) fn add_explanation_to_diagnostic(
         &self,
         tcx: TyCtxt<'tcx>,
         body: &Body<'tcx>,
@@ -212,7 +212,7 @@
                                         "consider adding semicolon after the expression so its \
                                         temporaries are dropped sooner, before the local variables \
                                         declared by the block are dropped",
-                                        ";".to_string(),
+                                        ";",
                                         Applicability::MaybeIncorrect,
                                     );
                                 }
@@ -276,7 +276,7 @@
     pub(crate) fn add_lifetime_bound_suggestion_to_diagnostic(
         &self,
         err: &mut Diagnostic,
-        category: &ConstraintCategory,
+        category: &ConstraintCategory<'tcx>,
         span: Span,
         region_name: &RegionName,
     ) {
@@ -305,7 +305,7 @@
         &self,
         borrow_region: RegionVid,
         outlived_region: RegionVid,
-    ) -> (ConstraintCategory, bool, Span, Option<RegionName>) {
+    ) -> (ConstraintCategory<'tcx>, bool, Span, Option<RegionName>) {
         let BlameConstraint { category, from_closure, cause, variance_info: _ } =
             self.regioncx.best_blame_constraint(
                 &self.body,
@@ -337,7 +337,7 @@
         location: Location,
         borrow: &BorrowData<'tcx>,
         kind_place: Option<(WriteKind, Place<'tcx>)>,
-    ) -> BorrowExplanation {
+    ) -> BorrowExplanation<'tcx> {
         debug!(
             "explain_why_borrow_contains_point(location={:?}, borrow={:?}, kind_place={:?})",
             location, borrow, kind_place
@@ -467,7 +467,7 @@
                     block
                         .terminator()
                         .successors()
-                        .map(|bb| Location { statement_index: 0, block: *bb })
+                        .map(|bb| Location { statement_index: 0, block: bb })
                         .filter(|s| visited_locations.insert(*s))
                         .map(|s| {
                             if self.is_back_edge(location, s) {
@@ -526,7 +526,7 @@
                 }
             } else {
                 for bb in block.terminator().successors() {
-                    let successor = Location { statement_index: 0, block: *bb };
+                    let successor = Location { statement_index: 0, block: bb };
 
                     if !visited_locations.contains(&successor)
                         && self.find_loop_head_dfs(successor, loop_head, visited_locations)
@@ -705,10 +705,10 @@
                 let terminator = block.terminator();
                 debug!("was_captured_by_trait_object: terminator={:?}", terminator);
 
-                if let TerminatorKind::Call { destination: Some((place, block)), args, .. } =
+                if let TerminatorKind::Call { destination, target: Some(block), args, .. } =
                     &terminator.kind
                 {
-                    if let Some(dest) = place.as_local() {
+                    if let Some(dest) = destination.as_local() {
                         debug!(
                             "was_captured_by_trait_object: target={:?} dest={:?} args={:?}",
                             target, dest, args
diff --git a/compiler/rustc_borrowck/src/diagnostics/find_use.rs b/compiler/rustc_borrowck/src/diagnostics/find_use.rs
index ab4536f..06fca4d 100644
--- a/compiler/rustc_borrowck/src/diagnostics/find_use.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/find_use.rs
@@ -11,7 +11,7 @@
 use rustc_middle::mir::{Body, Local, Location};
 use rustc_middle::ty::{RegionVid, TyCtxt};
 
-crate fn find<'tcx>(
+pub(crate) fn find<'tcx>(
     body: &Body<'tcx>,
     regioncx: &Rc<RegionInferenceContext<'tcx>>,
     tcx: TyCtxt<'tcx>,
@@ -67,8 +67,8 @@
                             block_data
                                 .terminator()
                                 .successors()
-                                .filter(|&bb| Some(&Some(*bb)) != block_data.terminator().unwind())
-                                .map(|&bb| Location { statement_index: 0, block: bb }),
+                                .filter(|&bb| Some(&Some(bb)) != block_data.terminator().unwind())
+                                .map(|bb| Location { statement_index: 0, block: bb }),
                         );
                     }
                 }
diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs
index 05d2950..fbc3a8c 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mod.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs
@@ -35,12 +35,12 @@
 mod mutability_errors;
 mod region_errors;
 
-crate use bound_region_errors::{ToUniverseInfo, UniverseInfo};
-crate use mutability_errors::AccessKind;
-crate use outlives_suggestion::OutlivesSuggestionBuilder;
-crate use region_errors::{ErrorConstraintInfo, RegionErrorKind, RegionErrors};
-crate use region_name::{RegionName, RegionNameSource};
-crate use rustc_const_eval::util::CallKind;
+pub(crate) use bound_region_errors::{ToUniverseInfo, UniverseInfo};
+pub(crate) use mutability_errors::AccessKind;
+pub(crate) use outlives_suggestion::OutlivesSuggestionBuilder;
+pub(crate) use region_errors::{ErrorConstraintInfo, RegionErrorKind, RegionErrors};
+pub(crate) use region_name::{RegionName, RegionNameSource};
+pub(crate) use rustc_const_eval::util::CallKind;
 use rustc_middle::mir::tcx::PlaceTy;
 
 pub(super) struct IncludingDowncast(pub(super) bool);
@@ -896,7 +896,7 @@
         let hir_id = self.infcx.tcx.hir().local_def_id_to_hir_id(local_did);
         let expr = &self.infcx.tcx.hir().expect_expr(hir_id).kind;
         debug!("closure_span: hir_id={:?} expr={:?}", hir_id, expr);
-        if let hir::ExprKind::Closure(.., body_id, args_span, _) = expr {
+        if let hir::ExprKind::Closure { body, fn_decl_span, .. } = expr {
             for (captured_place, place) in self
                 .infcx
                 .tcx
@@ -909,11 +909,11 @@
                         if target_place == place.as_ref() =>
                     {
                         debug!("closure_span: found captured local {:?}", place);
-                        let body = self.infcx.tcx.hir().body(*body_id);
+                        let body = self.infcx.tcx.hir().body(*body);
                         let generator_kind = body.generator_kind();
 
                         return Some((
-                            *args_span,
+                            *fn_decl_span,
                             generator_kind,
                             captured_place.get_capture_kind_span(self.infcx.tcx),
                             captured_place.get_path_span(self.infcx.tcx),
@@ -1023,7 +1023,7 @@
                                      avoid moving into the `for` loop",
                                     ty,
                                 ),
-                                "&".to_string(),
+                                "&",
                                 Applicability::MaybeIncorrect,
                             );
                         }
@@ -1049,7 +1049,7 @@
                                             .map(|n| format!("`{}`", n))
                                             .unwrap_or_else(|| "the mutable reference".to_string()),
                                     ),
-                                    "&mut *".to_string(),
+                                    "&mut *",
                                     Applicability::MachineApplicable,
                                 );
                             }
@@ -1067,7 +1067,7 @@
                         err.span_suggestion_verbose(
                             fn_call_span.shrink_to_lo(),
                             "consider calling `.as_ref()` to borrow the type's contents",
-                            "as_ref().".to_string(),
+                            "as_ref().",
                             Applicability::MachineApplicable,
                         );
                     }
diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
index e7fd89c..eb5e61f 100644
--- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
@@ -417,7 +417,7 @@
             err.span_suggestion_verbose(
                 span.shrink_to_hi(),
                 &format!("consider borrowing the `{}`'s content", diag_name.unwrap()),
-                ".as_ref()".to_string(),
+                ".as_ref()",
                 Applicability::MaybeIncorrect,
             );
         } else if let Some(use_spans) = use_spans {
diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
index fe5e3c5..861c5e9 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
@@ -295,7 +295,7 @@
                             err.span_suggestion_verbose(
                                 source_info.span.with_hi(source_info.span.lo() + BytePos(5)),
                                 "try removing `&mut` here",
-                                String::new(),
+                                "",
                                 Applicability::MachineApplicable,
                             );
                         } else {
@@ -316,7 +316,7 @@
                     err.span_suggestion_verbose(
                         decl.source_info.span.shrink_to_lo(),
                         "consider making the binding mutable",
-                        "mut ".to_string(),
+                        "mut ",
                         Applicability::MachineApplicable,
                     );
                 }
@@ -402,7 +402,7 @@
                 err.span_suggestion(
                     span,
                     "try removing `&mut` here",
-                    String::new(),
+                    "",
                     Applicability::MaybeIncorrect,
                 );
             }
diff --git a/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs b/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs
index ab9c206..d359d7e 100644
--- a/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs
@@ -62,7 +62,8 @@
             | RegionNameSource::AnonRegionFromUpvar(..)
             | RegionNameSource::AnonRegionFromOutput(..)
             | RegionNameSource::AnonRegionFromYieldTy(..)
-            | RegionNameSource::AnonRegionFromAsyncFn(..) => {
+            | RegionNameSource::AnonRegionFromAsyncFn(..)
+            | RegionNameSource::AnonRegionFromImplSignature(..) => {
                 debug!("Region {:?} is NOT suggestable", name);
                 false
             }
@@ -149,7 +150,7 @@
     }
 
     /// Add the outlives constraint `fr: outlived_fr` to the set of constraints we need to suggest.
-    crate fn collect_constraint(&mut self, fr: RegionVid, outlived_fr: RegionVid) {
+    pub(crate) fn collect_constraint(&mut self, fr: RegionVid, outlived_fr: RegionVid) {
         debug!("Collected {:?}: {:?}", fr, outlived_fr);
 
         // Add to set of constraints for final help note.
@@ -158,10 +159,10 @@
 
     /// Emit an intermediate note on the given `Diagnostic` if the involved regions are
     /// suggestable.
-    crate fn intermediate_suggestion(
+    pub(crate) fn intermediate_suggestion(
         &mut self,
         mbcx: &MirBorrowckCtxt<'_, '_>,
-        errci: &ErrorConstraintInfo,
+        errci: &ErrorConstraintInfo<'_>,
         diag: &mut Diagnostic,
     ) {
         // Emit an intermediate note.
@@ -179,7 +180,7 @@
 
     /// If there is a suggestion to emit, add a diagnostic to the buffer. This is the final
     /// suggestion including all collected constraints.
-    crate fn add_suggestion(&self, mbcx: &mut MirBorrowckCtxt<'_, '_>) {
+    pub(crate) fn add_suggestion(&self, mbcx: &mut MirBorrowckCtxt<'_, '_>) {
         // No constraints to add? Done.
         if self.constraints_to_add.is_empty() {
             debug!("No constraints to suggest.");
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
index 6f1c8da..e0f8da1 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
@@ -1,10 +1,14 @@
 //! Error reporting machinery for lifetime errors.
 
-use rustc_errors::{Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
+use rustc_data_structures::stable_set::FxHashSet;
+use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan};
+use rustc_hir::def_id::DefId;
+use rustc_hir::intravisit::Visitor;
+use rustc_hir::{self as hir, Item, ItemKind, Node};
 use rustc_infer::infer::{
     error_reporting::nice_region_error::{
         self, find_anon_type, find_param_with_region, suggest_adding_lifetime_params,
-        NiceRegionError,
+        HirTraitObjectVisitor, NiceRegionError, TraitObjectVisitor,
     },
     error_reporting::unexpected_hidden_region_diagnostic,
     NllRegionVariableOrigin, RelateParamBound,
@@ -12,8 +16,11 @@
 use rustc_middle::hir::place::PlaceBase;
 use rustc_middle::mir::{ConstraintCategory, ReturnConstraint};
 use rustc_middle::ty::subst::InternalSubsts;
+use rustc_middle::ty::Region;
+use rustc_middle::ty::TypeVisitor;
 use rustc_middle::ty::{self, RegionVid, Ty};
 use rustc_span::symbol::sym;
+use rustc_span::symbol::Ident;
 use rustc_span::Span;
 
 use crate::borrowck_errors;
@@ -27,7 +34,7 @@
     MirBorrowckCtxt,
 };
 
-impl ConstraintDescription for ConstraintCategory {
+impl<'tcx> ConstraintDescription for ConstraintCategory<'tcx> {
     fn description(&self) -> &'static str {
         // Must end with a space. Allows for empty names to be provided.
         match self {
@@ -37,7 +44,7 @@
             ConstraintCategory::UseAsConst => "using this value as a constant ",
             ConstraintCategory::UseAsStatic => "using this value as a static ",
             ConstraintCategory::Cast => "cast ",
-            ConstraintCategory::CallArgument => "argument ",
+            ConstraintCategory::CallArgument(_) => "argument ",
             ConstraintCategory::TypeAnnotation => "type annotation ",
             ConstraintCategory::ClosureBounds => "closure body ",
             ConstraintCategory::SizedBound => "proving this value is `Sized` ",
@@ -58,10 +65,10 @@
 ///
 /// Usually we expect this to either be empty or contain a small number of items, so we can avoid
 /// allocation most of the time.
-crate type RegionErrors<'tcx> = Vec<RegionErrorKind<'tcx>>;
+pub(crate) type RegionErrors<'tcx> = Vec<RegionErrorKind<'tcx>>;
 
 #[derive(Clone, Debug)]
-crate enum RegionErrorKind<'tcx> {
+pub(crate) enum RegionErrorKind<'tcx> {
     /// A generic bound failure for a type test (`T: 'a`).
     TypeTestError { type_test: TypeTest<'tcx> },
 
@@ -101,7 +108,7 @@
 
 /// Information about the various region constraints involved in a borrow checker error.
 #[derive(Clone, Debug)]
-pub struct ErrorConstraintInfo {
+pub struct ErrorConstraintInfo<'tcx> {
     // fr: outlived_fr
     pub(super) fr: RegionVid,
     pub(super) fr_is_local: bool,
@@ -109,7 +116,7 @@
     pub(super) outlived_fr_is_local: bool,
 
     // Category and span for best blame constraint
-    pub(super) category: ConstraintCategory,
+    pub(super) category: ConstraintCategory<'tcx>,
     pub(super) span: Span,
 }
 
@@ -256,6 +263,70 @@
         outlives_suggestion.add_suggestion(self);
     }
 
+    fn get_impl_ident_and_self_ty_from_trait(
+        &self,
+        def_id: DefId,
+        trait_objects: &FxHashSet<DefId>,
+    ) -> Option<(Ident, &'tcx hir::Ty<'tcx>)> {
+        let tcx = self.infcx.tcx;
+        match tcx.hir().get_if_local(def_id) {
+            Some(Node::ImplItem(impl_item)) => {
+                match tcx.hir().find_by_def_id(tcx.hir().get_parent_item(impl_item.hir_id())) {
+                    Some(Node::Item(Item {
+                        kind: ItemKind::Impl(hir::Impl { self_ty, .. }),
+                        ..
+                    })) => Some((impl_item.ident, self_ty)),
+                    _ => None,
+                }
+            }
+            Some(Node::TraitItem(trait_item)) => {
+                let trait_did = tcx.hir().get_parent_item(trait_item.hir_id());
+                match tcx.hir().find_by_def_id(trait_did) {
+                    Some(Node::Item(Item { kind: ItemKind::Trait(..), .. })) => {
+                        // The method being called is defined in the `trait`, but the `'static`
+                        // obligation comes from the `impl`. Find that `impl` so that we can point
+                        // at it in the suggestion.
+                        let trait_did = trait_did.to_def_id();
+                        match tcx
+                            .hir()
+                            .trait_impls(trait_did)
+                            .iter()
+                            .filter_map(|&impl_did| {
+                                match tcx.hir().get_if_local(impl_did.to_def_id()) {
+                                    Some(Node::Item(Item {
+                                        kind: ItemKind::Impl(hir::Impl { self_ty, .. }),
+                                        ..
+                                    })) if trait_objects.iter().all(|did| {
+                                        // FIXME: we should check `self_ty` against the receiver
+                                        // type in the `UnifyReceiver` context, but for now, use
+                                        // this imperfect proxy. This will fail if there are
+                                        // multiple `impl`s for the same trait like
+                                        // `impl Foo for Box<dyn Bar>` and `impl Foo for dyn Bar`.
+                                        // In that case, only the first one will get suggestions.
+                                        let mut traits = vec![];
+                                        let mut hir_v = HirTraitObjectVisitor(&mut traits, *did);
+                                        hir_v.visit_ty(self_ty);
+                                        !traits.is_empty()
+                                    }) =>
+                                    {
+                                        Some(self_ty)
+                                    }
+                                    _ => None,
+                                }
+                            })
+                            .next()
+                        {
+                            Some(self_ty) => Some((trait_item.ident, self_ty)),
+                            _ => None,
+                        }
+                    }
+                    _ => None,
+                }
+            }
+            _ => None,
+        }
+    }
+
     /// Report an error because the universal region `fr` was required to outlive
     /// `outlived_fr` but it is not known to do so. For example:
     ///
@@ -279,6 +350,7 @@
             });
 
         debug!("report_region_error: category={:?} {:?} {:?}", category, cause, variance_info);
+
         // Check if we can use one of the "nice region errors".
         if let (Some(f), Some(o)) = (self.to_error_region(fr), self.to_error_region(outlived_fr)) {
             let nice = NiceRegionError::new_from_span(self.infcx, cause.span, o, f);
@@ -312,7 +384,7 @@
                 self.report_fnmut_error(&errci, kind)
             }
             (ConstraintCategory::Assignment, true, false)
-            | (ConstraintCategory::CallArgument, true, false) => {
+            | (ConstraintCategory::CallArgument(_), true, false) => {
                 let mut db = self.report_escaping_data_error(&errci);
 
                 outlives_suggestion.intermediate_suggestion(self, &errci, &mut db);
@@ -405,7 +477,7 @@
     /// ```
     fn report_fnmut_error(
         &self,
-        errci: &ErrorConstraintInfo,
+        errci: &ErrorConstraintInfo<'tcx>,
         kind: ReturnConstraint,
     ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
         let ErrorConstraintInfo { outlived_fr, span, .. } = errci;
@@ -450,10 +522,10 @@
                 _ => None,
             };
 
-            if defined_hir.is_some() {
+            if let Some(def_hir) = defined_hir {
                 let upvars_map = self.infcx.tcx.upvars_mentioned(def_id).unwrap();
-                let upvar_def_span = self.infcx.tcx.hir().span(defined_hir.unwrap());
-                let upvar_span = upvars_map.get(&defined_hir.unwrap()).unwrap().span;
+                let upvar_def_span = self.infcx.tcx.hir().span(def_hir);
+                let upvar_span = upvars_map.get(&def_hir).unwrap().span;
                 diag.span_label(upvar_def_span, "variable defined here");
                 diag.span_label(upvar_span, "variable captured here");
             }
@@ -486,7 +558,7 @@
     /// ```
     fn report_escaping_data_error(
         &self,
-        errci: &ErrorConstraintInfo,
+        errci: &ErrorConstraintInfo<'tcx>,
     ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
         let ErrorConstraintInfo { span, category, .. } = errci;
 
@@ -548,24 +620,28 @@
         // Only show an extra note if we can find an 'error region' for both of the region
         // variables. This avoids showing a noisy note that just mentions 'synthetic' regions
         // that don't help the user understand the error.
-        if self.to_error_region(errci.fr).is_some()
-            && self.to_error_region(errci.outlived_fr).is_some()
-        {
-            let fr_region_name = self.give_region_a_name(errci.fr).unwrap();
-            fr_region_name.highlight_region_name(&mut diag);
-            let outlived_fr_region_name = self.give_region_a_name(errci.outlived_fr).unwrap();
-            outlived_fr_region_name.highlight_region_name(&mut diag);
+        match (self.to_error_region(errci.fr), self.to_error_region(errci.outlived_fr)) {
+            (Some(f), Some(o)) => {
+                self.maybe_suggest_constrain_dyn_trait_impl(&mut diag, f, o, category);
 
-            diag.span_label(
-                *span,
-                format!(
-                    "{}requires that `{}` must outlive `{}`",
-                    category.description(),
-                    fr_region_name,
-                    outlived_fr_region_name,
-                ),
-            );
+                let fr_region_name = self.give_region_a_name(errci.fr).unwrap();
+                fr_region_name.highlight_region_name(&mut diag);
+                let outlived_fr_region_name = self.give_region_a_name(errci.outlived_fr).unwrap();
+                outlived_fr_region_name.highlight_region_name(&mut diag);
+
+                diag.span_label(
+                    *span,
+                    format!(
+                        "{}requires that `{}` must outlive `{}`",
+                        category.description(),
+                        fr_region_name,
+                        outlived_fr_region_name,
+                    ),
+                );
+            }
+            _ => {}
         }
+
         diag
     }
 
@@ -586,7 +662,7 @@
     /// ```
     fn report_general_error(
         &self,
-        errci: &ErrorConstraintInfo,
+        errci: &ErrorConstraintInfo<'tcx>,
     ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
         let ErrorConstraintInfo {
             fr,
@@ -699,6 +775,100 @@
         }
     }
 
+    fn maybe_suggest_constrain_dyn_trait_impl(
+        &self,
+        diag: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>,
+        f: Region<'tcx>,
+        o: Region<'tcx>,
+        category: &ConstraintCategory<'tcx>,
+    ) {
+        if !o.is_static() {
+            return;
+        }
+
+        let tcx = self.infcx.tcx;
+
+        let instance = if let ConstraintCategory::CallArgument(Some(func_ty)) = category {
+            let (fn_did, substs) = match func_ty.kind() {
+                ty::FnDef(fn_did, substs) => (fn_did, substs),
+                _ => return,
+            };
+            debug!(?fn_did, ?substs);
+
+            // Only suggest this on function calls, not closures
+            let ty = tcx.type_of(fn_did);
+            debug!("ty: {:?}, ty.kind: {:?}", ty, ty.kind());
+            if let ty::Closure(_, _) = ty.kind() {
+                return;
+            }
+
+            if let Ok(Some(instance)) = ty::Instance::resolve(
+                tcx,
+                self.param_env,
+                *fn_did,
+                self.infcx.resolve_vars_if_possible(substs),
+            ) {
+                instance
+            } else {
+                return;
+            }
+        } else {
+            return;
+        };
+
+        let param = match find_param_with_region(tcx, f, o) {
+            Some(param) => param,
+            None => return,
+        };
+        debug!(?param);
+
+        let mut visitor = TraitObjectVisitor(FxHashSet::default());
+        visitor.visit_ty(param.param_ty);
+
+        let Some((ident, self_ty)) =
+            self.get_impl_ident_and_self_ty_from_trait(instance.def_id(), &visitor.0) else {return};
+
+        self.suggest_constrain_dyn_trait_in_impl(diag, &visitor.0, ident, self_ty);
+    }
+
+    #[instrument(skip(self, err), level = "debug")]
+    fn suggest_constrain_dyn_trait_in_impl(
+        &self,
+        err: &mut Diagnostic,
+        found_dids: &FxHashSet<DefId>,
+        ident: Ident,
+        self_ty: &hir::Ty<'_>,
+    ) -> bool {
+        debug!("err: {:#?}", err);
+        let mut suggested = false;
+        for found_did in found_dids {
+            let mut traits = vec![];
+            let mut hir_v = HirTraitObjectVisitor(&mut traits, *found_did);
+            hir_v.visit_ty(&self_ty);
+            debug!("trait spans found: {:?}", traits);
+            for span in &traits {
+                let mut multi_span: MultiSpan = vec![*span].into();
+                multi_span.push_span_label(
+                    *span,
+                    "this has an implicit `'static` lifetime requirement".to_string(),
+                );
+                multi_span.push_span_label(
+                    ident.span,
+                    "calling this method introduces the `impl`'s 'static` requirement".to_string(),
+                );
+                err.span_note(multi_span, "the used `impl` has a `'static` requirement");
+                err.span_suggestion_verbose(
+                    span.shrink_to_hi(),
+                    "consider relaxing the implicit `'static` requirement",
+                    " + '_",
+                    Applicability::MaybeIncorrect,
+                );
+                suggested = true;
+            }
+        }
+        suggested
+    }
+
     fn suggest_adding_lifetime_params(
         &self,
         diag: &mut Diagnostic,
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
index c4cef57..8f36995 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
@@ -6,7 +6,7 @@
 use rustc_hir::def::{DefKind, Res};
 use rustc_middle::ty::print::RegionHighlightMode;
 use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
-use rustc_middle::ty::{self, RegionVid, Ty};
+use rustc_middle::ty::{self, DefIdTree, RegionVid, Ty};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{Span, DUMMY_SP};
 
@@ -15,18 +15,18 @@
 /// A name for a particular region used in emitting diagnostics. This name could be a generated
 /// name like `'1`, a name used by the user like `'a`, or a name like `'static`.
 #[derive(Debug, Clone)]
-crate struct RegionName {
+pub(crate) struct RegionName {
     /// The name of the region (interned).
-    crate name: Symbol,
+    pub(crate) name: Symbol,
     /// Where the region comes from.
-    crate source: RegionNameSource,
+    pub(crate) source: RegionNameSource,
 }
 
 /// Denotes the source of a region that is named by a `RegionName`. For example, a free region that
 /// was named by the user would get `NamedFreeRegion` and `'static` lifetime would get `Static`.
 /// This helps to print the right kinds of diagnostics.
 #[derive(Debug, Clone)]
-crate enum RegionNameSource {
+pub(crate) enum RegionNameSource {
     /// A bound (not free) region that was substituted at the def site (not an HRTB).
     NamedEarlyBoundRegion(Span),
     /// A free region that the user has a name (`'a`) for.
@@ -45,12 +45,14 @@
     AnonRegionFromYieldTy(Span, String),
     /// An anonymous region from an async fn.
     AnonRegionFromAsyncFn(Span),
+    /// An anonymous region from an impl self type or trait
+    AnonRegionFromImplSignature(Span, &'static str),
 }
 
 /// Describes what to highlight to explain to the user that we're giving an anonymous region a
 /// synthesized name, and how to highlight it.
 #[derive(Debug, Clone)]
-crate enum RegionNameHighlight {
+pub(crate) enum RegionNameHighlight {
     /// The anonymous region corresponds to a reference that was found by traversing the type in the HIR.
     MatchedHirTy(Span),
     /// The anonymous region corresponds to a `'_` in the generics list of a struct/enum/union.
@@ -65,7 +67,7 @@
 }
 
 impl RegionName {
-    crate fn was_named(&self) -> bool {
+    pub(crate) fn was_named(&self) -> bool {
         match self.source {
             RegionNameSource::NamedEarlyBoundRegion(..)
             | RegionNameSource::NamedFreeRegion(..)
@@ -75,11 +77,12 @@
             | RegionNameSource::AnonRegionFromUpvar(..)
             | RegionNameSource::AnonRegionFromOutput(..)
             | RegionNameSource::AnonRegionFromYieldTy(..)
-            | RegionNameSource::AnonRegionFromAsyncFn(..) => false,
+            | RegionNameSource::AnonRegionFromAsyncFn(..)
+            | RegionNameSource::AnonRegionFromImplSignature(..) => false,
         }
     }
 
-    crate fn span(&self) -> Option<Span> {
+    pub(crate) fn span(&self) -> Option<Span> {
         match self.source {
             RegionNameSource::Static => None,
             RegionNameSource::NamedEarlyBoundRegion(span)
@@ -87,7 +90,8 @@
             | RegionNameSource::SynthesizedFreeEnvRegion(span, _)
             | RegionNameSource::AnonRegionFromUpvar(span, _)
             | RegionNameSource::AnonRegionFromYieldTy(span, _)
-            | RegionNameSource::AnonRegionFromAsyncFn(span) => Some(span),
+            | RegionNameSource::AnonRegionFromAsyncFn(span)
+            | RegionNameSource::AnonRegionFromImplSignature(span, _) => Some(span),
             RegionNameSource::AnonRegionFromArgument(ref highlight)
             | RegionNameSource::AnonRegionFromOutput(ref highlight, _) => match *highlight {
                 RegionNameHighlight::MatchedHirTy(span)
@@ -98,7 +102,7 @@
         }
     }
 
-    crate fn highlight_region_name(&self, diag: &mut Diagnostic) {
+    pub(crate) fn highlight_region_name(&self, diag: &mut Diagnostic) {
         match &self.source {
             RegionNameSource::NamedFreeRegion(span)
             | RegionNameSource::NamedEarlyBoundRegion(span) => {
@@ -166,6 +170,12 @@
             RegionNameSource::AnonRegionFromYieldTy(span, type_name) => {
                 diag.span_label(*span, format!("yield type is {type_name}"));
             }
+            RegionNameSource::AnonRegionFromImplSignature(span, location) => {
+                diag.span_label(
+                    *span,
+                    format!("lifetime `{self}` appears in the `impl`'s {location}"),
+                );
+            }
             RegionNameSource::Static => {}
         }
     }
@@ -178,11 +188,11 @@
 }
 
 impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
-    crate fn mir_def_id(&self) -> hir::def_id::LocalDefId {
+    pub(crate) fn mir_def_id(&self) -> hir::def_id::LocalDefId {
         self.body.source.def_id().as_local().unwrap()
     }
 
-    crate fn mir_hir_id(&self) -> hir::HirId {
+    pub(crate) fn mir_hir_id(&self) -> hir::HirId {
         self.infcx.tcx.hir().local_def_id_to_hir_id(self.mir_def_id())
     }
 
@@ -222,7 +232,7 @@
     /// ```
     ///
     /// and then return the name `'1` for us to use.
-    crate fn give_region_a_name(&self, fr: RegionVid) -> Option<RegionName> {
+    pub(crate) fn give_region_a_name(&self, fr: RegionVid) -> Option<RegionName> {
         debug!(
             "give_region_a_name(fr={:?}, counter={:?})",
             fr,
@@ -240,7 +250,8 @@
             .or_else(|| self.give_name_if_anonymous_region_appears_in_arguments(fr))
             .or_else(|| self.give_name_if_anonymous_region_appears_in_upvars(fr))
             .or_else(|| self.give_name_if_anonymous_region_appears_in_output(fr))
-            .or_else(|| self.give_name_if_anonymous_region_appears_in_yield_ty(fr));
+            .or_else(|| self.give_name_if_anonymous_region_appears_in_yield_ty(fr))
+            .or_else(|| self.give_name_if_anonymous_region_appears_in_impl_signature(fr));
 
         if let Some(ref value) = value {
             self.region_names.try_borrow_mut().unwrap().insert(fr, value.clone());
@@ -254,6 +265,7 @@
     /// *user* has a name for. In that case, we'll be able to map
     /// `fr` to a `Region<'tcx>`, and that region will be one of
     /// named variants.
+    #[tracing::instrument(level = "trace", skip(self))]
     fn give_name_from_error_region(&self, fr: RegionVid) -> Option<RegionName> {
         let error_region = self.to_error_region(fr)?;
 
@@ -290,7 +302,7 @@
                     if free_region.bound_region.is_named() {
                         // A named region that is actually named.
                         Some(RegionName { name, source: RegionNameSource::NamedFreeRegion(span) })
-                    } else {
+                    } else if let hir::IsAsync::Async = tcx.asyncness(self.mir_hir_id().owner) {
                         // If we spuriously thought that the region is named, we should let the
                         // system generate a true name for error messages. Currently this can
                         // happen if we have an elided name in an async fn for example: the
@@ -301,6 +313,8 @@
                             name,
                             source: RegionNameSource::AnonRegionFromAsyncFn(span),
                         })
+                    } else {
+                        None
                     }
                 }
 
@@ -311,8 +325,9 @@
                         // Can't have BrEnv in functions, constants or generators.
                         bug!("BrEnv outside of closure.");
                     };
-                    let hir::ExprKind::Closure(_, _, _, args_span, _) =
-                        tcx.hir().expect_expr(self.mir_hir_id()).kind else {
+                    let hir::ExprKind::Closure { fn_decl_span, .. }
+                        = tcx.hir().expect_expr(self.mir_hir_id()).kind
+                    else {
                         bug!("Closure is not defined by a closure expr");
                     };
                     let region_name = self.synthesize_region_name();
@@ -336,7 +351,7 @@
                     Some(RegionName {
                         name: region_name,
                         source: RegionNameSource::SynthesizedFreeEnvRegion(
-                            args_span,
+                            fn_decl_span,
                             note.to_string(),
                         ),
                     })
@@ -361,6 +376,7 @@
     ///  | fn foo(x: &u32) { .. }
     ///           ------- fully elaborated type of `x` is `&'1 u32`
     /// ```
+    #[tracing::instrument(level = "trace", skip(self))]
     fn give_name_if_anonymous_region_appears_in_arguments(
         &self,
         fr: RegionVid,
@@ -567,15 +583,17 @@
         let lifetime =
             self.try_match_adt_and_generic_args(substs, needle_fr, args, search_stack)?;
         match lifetime.name {
-            hir::LifetimeName::Param(_)
+            hir::LifetimeName::Param(_, hir::ParamName::Plain(_) | hir::ParamName::Error)
             | hir::LifetimeName::Error
-            | hir::LifetimeName::Static
-            | hir::LifetimeName::Underscore => {
+            | hir::LifetimeName::Static => {
                 let lifetime_span = lifetime.span;
                 Some(RegionNameHighlight::MatchedAdtAndSegment(lifetime_span))
             }
 
-            hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Implicit => {
+            hir::LifetimeName::Param(_, hir::ParamName::Fresh)
+            | hir::LifetimeName::ImplicitObjectLifetimeDefault
+            | hir::LifetimeName::Implicit
+            | hir::LifetimeName::Underscore => {
                 // In this case, the user left off the lifetime; so
                 // they wrote something like:
                 //
@@ -648,6 +666,7 @@
     ///  | let x = Some(&22);
     ///        - fully elaborated type of `x` is `Option<&'1 u32>`
     /// ```
+    #[tracing::instrument(level = "trace", skip(self))]
     fn give_name_if_anonymous_region_appears_in_upvars(&self, fr: RegionVid) -> Option<RegionName> {
         let upvar_index = self.regioncx.get_upvar_index_for_region(self.infcx.tcx, fr)?;
         let (upvar_name, upvar_span) = self.regioncx.get_upvar_name_and_span_for_region(
@@ -667,6 +686,7 @@
     /// must be a closure since, in a free fn, such an argument would
     /// have to either also appear in an argument (if using elision)
     /// or be early bound (named, not in argument).
+    #[tracing::instrument(level = "trace", skip(self))]
     fn give_name_if_anonymous_region_appears_in_output(&self, fr: RegionVid) -> Option<RegionName> {
         let tcx = self.infcx.tcx;
         let hir = tcx.hir();
@@ -681,16 +701,16 @@
 
         let (return_span, mir_description, hir_ty) = match hir.get(mir_hir_id) {
             hir::Node::Expr(hir::Expr {
-                kind: hir::ExprKind::Closure(_, return_ty, body_id, span, _),
+                kind: hir::ExprKind::Closure { fn_decl, body, fn_decl_span, .. },
                 ..
             }) => {
-                let (mut span, mut hir_ty) = match return_ty.output {
+                let (mut span, mut hir_ty) = match fn_decl.output {
                     hir::FnRetTy::DefaultReturn(_) => {
-                        (tcx.sess.source_map().end_point(*span), None)
+                        (tcx.sess.source_map().end_point(*fn_decl_span), None)
                     }
-                    hir::FnRetTy::Return(hir_ty) => (return_ty.output.span(), Some(hir_ty)),
+                    hir::FnRetTy::Return(hir_ty) => (fn_decl.output.span(), Some(hir_ty)),
                 };
-                let mir_description = match hir.body(*body_id).generator_kind {
+                let mir_description = match hir.body(*body).generator_kind {
                     Some(hir::GeneratorKind::Async(gen)) => match gen {
                         hir::AsyncGeneratorKind::Block => " of async block",
                         hir::AsyncGeneratorKind::Closure => " of async closure",
@@ -798,6 +818,7 @@
         }
     }
 
+    #[tracing::instrument(level = "trace", skip(self))]
     fn give_name_if_anonymous_region_appears_in_yield_ty(
         &self,
         fr: RegionVid,
@@ -820,8 +841,9 @@
 
         let yield_span = match tcx.hir().get(self.mir_hir_id()) {
             hir::Node::Expr(hir::Expr {
-                kind: hir::ExprKind::Closure(_, _, _, span, _), ..
-            }) => (tcx.sess.source_map().end_point(*span)),
+                kind: hir::ExprKind::Closure { fn_decl_span, .. },
+                ..
+            }) => (tcx.sess.source_map().end_point(*fn_decl_span)),
             _ => self.body.span,
         };
 
@@ -836,4 +858,43 @@
             source: RegionNameSource::AnonRegionFromYieldTy(yield_span, type_name),
         })
     }
+
+    fn give_name_if_anonymous_region_appears_in_impl_signature(
+        &self,
+        fr: RegionVid,
+    ) -> Option<RegionName> {
+        let ty::ReEarlyBound(region) = *self.to_error_region(fr)? else {
+            return None;
+        };
+        if region.has_name() {
+            return None;
+        };
+
+        let tcx = self.infcx.tcx;
+        let body_parent_did = tcx.opt_parent(self.mir_def_id().to_def_id())?;
+        if tcx.parent(region.def_id) != body_parent_did
+            || tcx.def_kind(body_parent_did) != DefKind::Impl
+        {
+            return None;
+        }
+
+        let mut found = false;
+        tcx.fold_regions(tcx.type_of(body_parent_did), &mut true, |r: ty::Region<'tcx>, _| {
+            if *r == ty::ReEarlyBound(region) {
+                found = true;
+            }
+            r
+        });
+
+        Some(RegionName {
+            name: self.synthesize_region_name(),
+            source: RegionNameSource::AnonRegionFromImplSignature(
+                tcx.def_span(region.def_id),
+                // FIXME(compiler-errors): Does this ever actually show up
+                // anywhere other than the self type? I couldn't create an
+                // example of a `'_` in the impl's trait being referenceable.
+                if found { "self type" } else { "header" },
+            ),
+        })
+    }
 }
diff --git a/compiler/rustc_borrowck/src/diagnostics/var_name.rs b/compiler/rustc_borrowck/src/diagnostics/var_name.rs
index 00f6280..9ba29f0 100644
--- a/compiler/rustc_borrowck/src/diagnostics/var_name.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/var_name.rs
@@ -7,7 +7,7 @@
 use rustc_span::symbol::Symbol;
 
 impl<'tcx> RegionInferenceContext<'tcx> {
-    crate fn get_var_name_and_span_for_region(
+    pub(crate) fn get_var_name_and_span_for_region(
         &self,
         tcx: TyCtxt<'tcx>,
         body: &Body<'tcx>,
@@ -34,7 +34,11 @@
     }
 
     /// Search the upvars (if any) to find one that references fr. Return its index.
-    crate fn get_upvar_index_for_region(&self, tcx: TyCtxt<'tcx>, fr: RegionVid) -> Option<usize> {
+    pub(crate) fn get_upvar_index_for_region(
+        &self,
+        tcx: TyCtxt<'tcx>,
+        fr: RegionVid,
+    ) -> Option<usize> {
         let upvar_index =
             self.universal_regions().defining_ty.upvar_tys().position(|upvar_ty| {
                 debug!("get_upvar_index_for_region: upvar_ty={:?}", upvar_ty);
@@ -57,7 +61,7 @@
 
     /// Given the index of an upvar, finds its name and the span from where it was
     /// declared.
-    crate fn get_upvar_name_and_span_for_region(
+    pub(crate) fn get_upvar_name_and_span_for_region(
         &self,
         tcx: TyCtxt<'tcx>,
         upvars: &[Upvar<'tcx>],
@@ -81,7 +85,7 @@
     ///
     /// N.B., in the case of a closure, the index is indexing into the signature as seen by the
     /// user - in particular, index 0 is not the implicit self parameter.
-    crate fn get_argument_index_for_region(
+    pub(crate) fn get_argument_index_for_region(
         &self,
         tcx: TyCtxt<'tcx>,
         fr: RegionVid,
@@ -107,7 +111,7 @@
 
     /// Given the index of an argument, finds its name (if any) and the span from where it was
     /// declared.
-    crate fn get_argument_name_and_span_for_region(
+    pub(crate) fn get_argument_name_and_span_for_region(
         &self,
         body: &Body<'tcx>,
         local_names: &IndexVec<Local, Option<Symbol>>,
diff --git a/compiler/rustc_borrowck/src/facts.rs b/compiler/rustc_borrowck/src/facts.rs
index 86b719b..7f0a637 100644
--- a/compiler/rustc_borrowck/src/facts.rs
+++ b/compiler/rustc_borrowck/src/facts.rs
@@ -25,7 +25,7 @@
 
 pub type AllFacts = PoloniusFacts<RustcFacts>;
 
-crate trait AllFactsExt {
+pub(crate) trait AllFactsExt {
     /// Returns `true` if there is a need to gather `AllFacts` given the
     /// current `-Z` flags.
     fn enabled(tcx: TyCtxt<'_>) -> bool;
diff --git a/compiler/rustc_borrowck/src/invalidation.rs b/compiler/rustc_borrowck/src/invalidation.rs
index 76d240b..0425c53 100644
--- a/compiler/rustc_borrowck/src/invalidation.rs
+++ b/compiler/rustc_borrowck/src/invalidation.rs
@@ -124,6 +124,7 @@
                 ref func,
                 ref args,
                 destination,
+                target: _,
                 cleanup: _,
                 from_hir_call: _,
                 fn_span: _,
@@ -132,9 +133,7 @@
                 for arg in args {
                     self.consume_operand(location, arg);
                 }
-                if let Some((dest, _ /*bb*/)) = destination {
-                    self.mutate_place(location, *dest, Deep);
-                }
+                self.mutate_place(location, *destination, Deep);
             }
             TerminatorKind::Assert { ref cond, expected: _, ref msg, target: _, cleanup: _ } => {
                 self.consume_operand(location, cond);
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index 4661805..8ef2974 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -2,7 +2,6 @@
 
 #![allow(rustc::potential_query_instability)]
 #![feature(box_patterns)]
-#![feature(crate_visibility_modifier)]
 #![feature(let_chains)]
 #![feature(let_else)]
 #![feature(min_specialization)]
@@ -99,7 +98,11 @@
     by_ref: bool,
 }
 
-const DEREF_PROJECTION: &[PlaceElem<'_>; 1] = &[ProjectionElem::Deref];
+/// Associate some local constants with the `'tcx` lifetime
+struct TyCtxtConsts<'tcx>(TyCtxt<'tcx>);
+impl<'tcx> TyCtxtConsts<'tcx> {
+    const DEREF_PROJECTION: &'tcx [PlaceElem<'tcx>; 1] = &[ProjectionElem::Deref];
+}
 
 pub fn provide(providers: &mut Providers) {
     *providers = Providers {
@@ -423,7 +426,7 @@
                 .span_suggestion_short(
                     mut_span,
                     "remove this `mut`",
-                    String::new(),
+                    "",
                     Applicability::MachineApplicable,
                 )
                 .emit();
@@ -662,7 +665,8 @@
             TerminatorKind::Call {
                 ref func,
                 ref args,
-                ref destination,
+                destination,
+                target: _,
                 cleanup: _,
                 from_hir_call: _,
                 fn_span: _,
@@ -671,9 +675,7 @@
                 for arg in args {
                     self.consume_operand(loc, (arg, span), flow_state);
                 }
-                if let Some((dest, _ /*bb*/)) = *destination {
-                    self.mutate_place(loc, (dest, span), Deep, flow_state);
-                }
+                self.mutate_place(loc, (destination, span), Deep, flow_state);
             }
             TerminatorKind::Assert { ref cond, expected: _, ref msg, target: _, cleanup: _ } => {
                 self.consume_operand(loc, (cond, span), flow_state);
@@ -1445,7 +1447,7 @@
                 // Thread-locals might be dropped after the function exits
                 // We have to dereference the outer reference because
                 // borrows don't conflict behind shared references.
-                root_place.projection = DEREF_PROJECTION;
+                root_place.projection = TyCtxtConsts::DEREF_PROJECTION;
                 (true, true)
             } else {
                 (false, self.locals_are_invalidated_at_exit)
diff --git a/compiler/rustc_borrowck/src/location.rs b/compiler/rustc_borrowck/src/location.rs
index c89da55..70a3116 100644
--- a/compiler/rustc_borrowck/src/location.rs
+++ b/compiler/rustc_borrowck/src/location.rs
@@ -30,7 +30,7 @@
 }
 
 impl LocationTable {
-    crate fn new(body: &Body<'_>) -> Self {
+    pub(crate) fn new(body: &Body<'_>) -> Self {
         let mut num_points = 0;
         let statements_before_block = body
             .basic_blocks()
diff --git a/compiler/rustc_borrowck/src/member_constraints.rs b/compiler/rustc_borrowck/src/member_constraints.rs
index f920d9d..e91fcf1 100644
--- a/compiler/rustc_borrowck/src/member_constraints.rs
+++ b/compiler/rustc_borrowck/src/member_constraints.rs
@@ -1,3 +1,4 @@
+use rustc_data_structures::captures::Captures;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_index::vec::IndexVec;
 use rustc_middle::infer::MemberConstraint;
@@ -8,7 +9,7 @@
 
 /// Compactly stores a set of `R0 member of [R1...Rn]` constraints,
 /// indexed by the region `R0`.
-crate struct MemberConstraintSet<'tcx, R>
+pub(crate) struct MemberConstraintSet<'tcx, R>
 where
     R: Copy + Eq,
 {
@@ -28,17 +29,17 @@
 }
 
 /// Represents a `R0 member of [R1..Rn]` constraint
-crate struct NllMemberConstraint<'tcx> {
+pub(crate) struct NllMemberConstraint<'tcx> {
     next_constraint: Option<NllMemberConstraintIndex>,
 
     /// The span where the hidden type was instantiated.
-    crate definition_span: Span,
+    pub(crate) definition_span: Span,
 
     /// The hidden type in which `R0` appears. (Used in error reporting.)
-    crate hidden_ty: Ty<'tcx>,
+    pub(crate) hidden_ty: Ty<'tcx>,
 
     /// The region `R0`.
-    crate member_region_vid: ty::RegionVid,
+    pub(crate) member_region_vid: ty::RegionVid,
 
     /// Index of `R1` in `choice_regions` vector from `MemberConstraintSet`.
     start_index: usize,
@@ -48,7 +49,7 @@
 }
 
 rustc_index::newtype_index! {
-    crate struct NllMemberConstraintIndex {
+    pub(crate) struct NllMemberConstraintIndex {
         DEBUG_FORMAT = "MemberConstraintIndex({})"
     }
 }
@@ -73,7 +74,7 @@
     /// within into `RegionVid` format -- it typically consults the
     /// `UniversalRegions` data structure that is known to the caller
     /// (but which this code is unaware of).
-    crate fn push_constraint(
+    pub(crate) fn push_constraint(
         &mut self,
         m_c: &MemberConstraint<'tcx>,
         mut to_region_vid: impl FnMut(ty::Region<'tcx>) -> ty::RegionVid,
@@ -106,7 +107,7 @@
     /// the original `RegionVid` to an scc index. In some cases, we
     /// may have multiple `R1` values mapping to the same `R2` key -- that
     /// is ok, the two sets will be merged.
-    crate fn into_mapped<R2>(
+    pub(crate) fn into_mapped<R2>(
         self,
         mut map_fn: impl FnMut(R1) -> R2,
     ) -> MemberConstraintSet<'tcx, R2>
@@ -140,21 +141,23 @@
     }
 }
 
-impl<R> MemberConstraintSet<'_, R>
+impl<'tcx, R> MemberConstraintSet<'tcx, R>
 where
     R: Copy + Hash + Eq,
 {
-    crate fn all_indices(&self) -> impl Iterator<Item = NllMemberConstraintIndex> + '_ {
+    pub(crate) fn all_indices(
+        &self,
+    ) -> impl Iterator<Item = NllMemberConstraintIndex> + Captures<'tcx> + '_ {
         self.constraints.indices()
     }
 
     /// Iterate down the constraint indices associated with a given
     /// peek-region.  You can then use `choice_regions` and other
     /// methods to access data.
-    crate fn indices(
+    pub(crate) fn indices(
         &self,
         member_region_vid: R,
-    ) -> impl Iterator<Item = NllMemberConstraintIndex> + '_ {
+    ) -> impl Iterator<Item = NllMemberConstraintIndex> + Captures<'tcx> + '_ {
         let mut next = self.first_constraints.get(&member_region_vid).cloned();
         std::iter::from_fn(move || -> Option<NllMemberConstraintIndex> {
             if let Some(current) = next {
@@ -172,7 +175,7 @@
     /// ```text
     /// R0 member of [R1..Rn]
     /// ```
-    crate fn choice_regions(&self, pci: NllMemberConstraintIndex) -> &[ty::RegionVid] {
+    pub(crate) fn choice_regions(&self, pci: NllMemberConstraintIndex) -> &[ty::RegionVid] {
         let NllMemberConstraint { start_index, end_index, .. } = &self.constraints[pci];
         &self.choice_regions[*start_index..*end_index]
     }
diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs
index 927eb08..3a919e9 100644
--- a/compiler/rustc_borrowck/src/nll.rs
+++ b/compiler/rustc_borrowck/src/nll.rs
@@ -42,7 +42,7 @@
 
 /// The output of `nll::compute_regions`. This includes the computed `RegionInferenceContext`, any
 /// closure requirements to propagate, and any generated errors.
-crate struct NllOutput<'tcx> {
+pub(crate) struct NllOutput<'tcx> {
     pub regioncx: RegionInferenceContext<'tcx>,
     pub opaque_type_values: VecMap<DefId, OpaqueHiddenType<'tcx>>,
     pub polonius_input: Option<Box<AllFacts>>,
@@ -108,7 +108,7 @@
                     // We are at the terminator of an init that has a panic path,
                     // and where the init should not happen on panic
 
-                    for &successor in block_data.terminator().successors() {
+                    for successor in block_data.terminator().successors() {
                         if body[successor].is_cleanup {
                             continue;
                         }
@@ -299,7 +299,7 @@
 
     // Solve the region constraints.
     let (closure_region_requirements, nll_errors) =
-        regioncx.solve(infcx, &body, polonius_output.clone());
+        regioncx.solve(infcx, param_env, &body, polonius_output.clone());
 
     if !nll_errors.is_empty() {
         // Suppress unhelpful extra errors in `infer_opaque_types`.
@@ -457,6 +457,6 @@
     }
 }
 
-crate trait ConstraintDescription {
+pub(crate) trait ConstraintDescription {
     fn description(&self) -> &'static str;
 }
diff --git a/compiler/rustc_borrowck/src/place_ext.rs b/compiler/rustc_borrowck/src/place_ext.rs
index 83ff159..93d202e 100644
--- a/compiler/rustc_borrowck/src/place_ext.rs
+++ b/compiler/rustc_borrowck/src/place_ext.rs
@@ -5,7 +5,7 @@
 use rustc_middle::ty::{self, TyCtxt};
 
 /// Extension methods for the `Place` type.
-crate trait PlaceExt<'tcx> {
+pub(crate) trait PlaceExt<'tcx> {
     /// Returns `true` if we can safely ignore borrows of this place.
     /// This is true whenever there is no action that the user can do
     /// to the place `self` that would invalidate the borrow. This is true
diff --git a/compiler/rustc_borrowck/src/places_conflict.rs b/compiler/rustc_borrowck/src/places_conflict.rs
index 5a935c3..97335fd 100644
--- a/compiler/rustc_borrowck/src/places_conflict.rs
+++ b/compiler/rustc_borrowck/src/places_conflict.rs
@@ -14,7 +14,7 @@
 /// being run in the calling context, the conservative choice is to assume the compared indices
 /// are disjoint (and therefore, do not overlap).
 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
-crate enum PlaceConflictBias {
+pub(crate) enum PlaceConflictBias {
     Overlap,
     NoOverlap,
 }
@@ -22,7 +22,7 @@
 /// Helper function for checking if places conflict with a mutable borrow and deep access depth.
 /// This is used to check for places conflicting outside of the borrow checking code (such as in
 /// dataflow).
-crate fn places_conflict<'tcx>(
+pub(crate) fn places_conflict<'tcx>(
     tcx: TyCtxt<'tcx>,
     body: &Body<'tcx>,
     borrow_place: Place<'tcx>,
diff --git a/compiler/rustc_borrowck/src/region_infer/graphviz.rs b/compiler/rustc_borrowck/src/region_infer/graphviz.rs
index 95048d5..f31ccd7 100644
--- a/compiler/rustc_borrowck/src/region_infer/graphviz.rs
+++ b/compiler/rustc_borrowck/src/region_infer/graphviz.rs
@@ -11,12 +11,12 @@
 
 impl<'tcx> RegionInferenceContext<'tcx> {
     /// Write out the region constraint graph.
-    crate fn dump_graphviz_raw_constraints(&self, mut w: &mut dyn Write) -> io::Result<()> {
+    pub(crate) fn dump_graphviz_raw_constraints(&self, mut w: &mut dyn Write) -> io::Result<()> {
         dot::render(&RawConstraints { regioncx: self }, &mut w)
     }
 
     /// Write out the region constraint graph.
-    crate fn dump_graphviz_scc_constraints(&self, mut w: &mut dyn Write) -> io::Result<()> {
+    pub(crate) fn dump_graphviz_scc_constraints(&self, mut w: &mut dyn Write) -> io::Result<()> {
         let mut nodes_per_scc: IndexVec<ConstraintSccIndex, _> =
             self.constraint_sccs.all_sccs().map(|_| Vec::new()).collect();
 
diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs
index b2fa16c..44a0e62 100644
--- a/compiler/rustc_borrowck/src/region_infer/mod.rs
+++ b/compiler/rustc_borrowck/src/region_infer/mod.rs
@@ -10,7 +10,8 @@
 use rustc_hir::CRATE_HIR_ID;
 use rustc_index::vec::IndexVec;
 use rustc_infer::infer::canonical::QueryOutlivesConstraint;
-use rustc_infer::infer::region_constraints::{GenericKind, VarInfos, VerifyBound};
+use rustc_infer::infer::outlives::test_type_match;
+use rustc_infer::infer::region_constraints::{GenericKind, VarInfos, VerifyBound, VerifyIfEq};
 use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin};
 use rustc_middle::mir::{
     Body, ClosureOutlivesRequirement, ClosureOutlivesSubject, ClosureRegionRequirements,
@@ -46,6 +47,7 @@
 
 pub struct RegionInferenceContext<'tcx> {
     pub var_infos: VarInfos,
+
     /// Contains the definition for every region variable. Region
     /// variables are identified by their index (`RegionVid`). The
     /// definition contains information about where the region came
@@ -87,7 +89,7 @@
 
     /// Map closure bounds to a `Span` that should be used for error reporting.
     closure_bounds_mapping:
-        FxHashMap<Location, FxHashMap<(RegionVid, RegionVid), (ConstraintCategory, Span)>>,
+        FxHashMap<Location, FxHashMap<(RegionVid, RegionVid), (ConstraintCategory<'tcx>, Span)>>,
 
     /// Map universe indexes to information on why we created it.
     universe_causes: FxHashMap<ty::UniverseIndex, UniverseInfo<'tcx>>,
@@ -259,7 +261,7 @@
         member_constraints_in: MemberConstraintSet<'tcx, RegionVid>,
         closure_bounds_mapping: FxHashMap<
             Location,
-            FxHashMap<(RegionVid, RegionVid), (ConstraintCategory, Span)>,
+            FxHashMap<(RegionVid, RegionVid), (ConstraintCategory<'tcx>, Span)>,
         >,
         universe_causes: FxHashMap<ty::UniverseIndex, UniverseInfo<'tcx>>,
         type_tests: Vec<TypeTest<'tcx>>,
@@ -500,7 +502,7 @@
     }
 
     /// Returns an iterator over all the region indices.
-    pub fn regions(&self) -> impl Iterator<Item = RegionVid> + '_ {
+    pub fn regions(&self) -> impl Iterator<Item = RegionVid> + 'tcx {
         self.definitions.indices()
     }
 
@@ -513,26 +515,26 @@
     }
 
     /// Adds annotations for `#[rustc_regions]`; see `UniversalRegions::annotate`.
-    crate fn annotate(&self, tcx: TyCtxt<'tcx>, err: &mut Diagnostic) {
+    pub(crate) fn annotate(&self, tcx: TyCtxt<'tcx>, err: &mut Diagnostic) {
         self.universal_regions.annotate(tcx, err)
     }
 
     /// Returns `true` if the region `r` contains the point `p`.
     ///
     /// Panics if called before `solve()` executes,
-    crate fn region_contains(&self, r: impl ToRegionVid, p: impl ToElementIndex) -> bool {
+    pub(crate) fn region_contains(&self, r: impl ToRegionVid, p: impl ToElementIndex) -> bool {
         let scc = self.constraint_sccs.scc(r.to_region_vid());
         self.scc_values.contains(scc, p)
     }
 
     /// Returns access to the value of `r` for debugging purposes.
-    crate fn region_value_str(&self, r: RegionVid) -> String {
+    pub(crate) fn region_value_str(&self, r: RegionVid) -> String {
         let scc = self.constraint_sccs.scc(r.to_region_vid());
         self.scc_values.region_value_str(scc)
     }
 
     /// Returns access to the value of `r` for debugging purposes.
-    crate fn region_universe(&self, r: RegionVid) -> ty::UniverseIndex {
+    pub(crate) fn region_universe(&self, r: RegionVid) -> ty::UniverseIndex {
         let scc = self.constraint_sccs.scc(r.to_region_vid());
         self.scc_universes[scc]
     }
@@ -559,6 +561,7 @@
     pub(super) fn solve(
         &mut self,
         infcx: &InferCtxt<'_, 'tcx>,
+        param_env: ty::ParamEnv<'tcx>,
         body: &Body<'tcx>,
         polonius_output: Option<Rc<PoloniusOutput>>,
     ) -> (Option<ClosureRegionRequirements<'tcx>>, RegionErrors<'tcx>) {
@@ -574,7 +577,13 @@
         // eagerly.
         let mut outlives_requirements = infcx.tcx.is_typeck_child(mir_def_id).then(Vec::new);
 
-        self.check_type_tests(infcx, body, outlives_requirements.as_mut(), &mut errors_buffer);
+        self.check_type_tests(
+            infcx,
+            param_env,
+            body,
+            outlives_requirements.as_mut(),
+            &mut errors_buffer,
+        );
 
         // In Polonius mode, the errors about missing universal region relations are in the output
         // and need to be emitted or propagated. Otherwise, we need to check whether the
@@ -823,6 +832,7 @@
     fn check_type_tests(
         &self,
         infcx: &InferCtxt<'_, 'tcx>,
+        param_env: ty::ParamEnv<'tcx>,
         body: &Body<'tcx>,
         mut propagated_outlives_requirements: Option<&mut Vec<ClosureOutlivesRequirement<'tcx>>>,
         errors_buffer: &mut RegionErrors<'tcx>,
@@ -839,7 +849,8 @@
 
             let generic_ty = type_test.generic_kind.to_ty(tcx);
             if self.eval_verify_bound(
-                tcx,
+                infcx,
+                param_env,
                 body,
                 generic_ty,
                 type_test.lower_bound,
@@ -851,6 +862,7 @@
             if let Some(propagated_outlives_requirements) = &mut propagated_outlives_requirements {
                 if self.try_promote_type_test(
                     infcx,
+                    param_env,
                     body,
                     type_test,
                     propagated_outlives_requirements,
@@ -904,9 +916,11 @@
     /// The idea then is to lower the `T: 'X` constraint into multiple
     /// bounds -- e.g., if `'X` is the union of two free lifetimes,
     /// `'1` and `'2`, then we would create `T: '1` and `T: '2`.
+    #[instrument(level = "debug", skip(self, infcx, propagated_outlives_requirements))]
     fn try_promote_type_test(
         &self,
         infcx: &InferCtxt<'_, 'tcx>,
+        param_env: ty::ParamEnv<'tcx>,
         body: &Body<'tcx>,
         type_test: &TypeTest<'tcx>,
         propagated_outlives_requirements: &mut Vec<ClosureOutlivesRequirement<'tcx>>,
@@ -920,11 +934,41 @@
             return false;
         };
 
+        debug!("subject = {:?}", subject);
+
+        let r_scc = self.constraint_sccs.scc(*lower_bound);
+
+        debug!(
+            "lower_bound = {:?} r_scc={:?} universe={:?}",
+            lower_bound, r_scc, self.scc_universes[r_scc]
+        );
+
+        // If the type test requires that `T: 'a` where `'a` is a
+        // placeholder from another universe, that effectively requires
+        // `T: 'static`, so we have to propagate that requirement.
+        //
+        // It doesn't matter *what* universe because the promoted `T` will
+        // always be in the root universe.
+        if let Some(p) = self.scc_values.placeholders_contained_in(r_scc).next() {
+            debug!("encountered placeholder in higher universe: {:?}, requiring 'static", p);
+            let static_r = self.universal_regions.fr_static;
+            propagated_outlives_requirements.push(ClosureOutlivesRequirement {
+                subject,
+                outlived_free_region: static_r,
+                blame_span: locations.span(body),
+                category: ConstraintCategory::Boring,
+            });
+
+            // we can return here -- the code below might push add'l constraints
+            // but they would all be weaker than this one.
+            return true;
+        }
+
         // For each region outlived by lower_bound find a non-local,
         // universal region (it may be the same region) and add it to
         // `ClosureOutlivesRequirement`.
-        let r_scc = self.constraint_sccs.scc(*lower_bound);
         for ur in self.scc_values.universal_regions_outlived_by(r_scc) {
+            debug!("universal_region_outlived_by ur={:?}", ur);
             // Check whether we can already prove that the "subject" outlives `ur`.
             // If so, we don't have to propagate this requirement to our caller.
             //
@@ -938,12 +982,17 @@
             // where `ur` is a local bound -- we are sometimes in a
             // position to prove things that our caller cannot.  See
             // #53570 for an example.
-            if self.eval_verify_bound(tcx, body, generic_ty, ur, &type_test.verify_bound) {
+            if self.eval_verify_bound(
+                infcx,
+                param_env,
+                body,
+                generic_ty,
+                ur,
+                &type_test.verify_bound,
+            ) {
                 continue;
             }
 
-            debug!("try_promote_type_test: ur={:?}", ur);
-
             let non_local_ub = self.universal_region_relations.non_local_upper_bounds(ur);
             debug!("try_promote_type_test: non_local_ub={:?}", non_local_ub);
 
@@ -980,6 +1029,7 @@
     /// will use it's *external name*, which will be a `RegionKind`
     /// variant that can be used in query responses such as
     /// `ReEarlyBound`.
+    #[instrument(level = "debug", skip(self, infcx))]
     fn try_promote_type_test_subject(
         &self,
         infcx: &InferCtxt<'_, 'tcx>,
@@ -987,8 +1037,6 @@
     ) -> Option<ClosureOutlivesSubject<'tcx>> {
         let tcx = infcx.tcx;
 
-        debug!("try_promote_type_test_subject(ty = {:?})", ty);
-
         let ty = tcx.fold_regions(ty, &mut false, |r, _depth| {
             let region_vid = self.to_region_vid(r);
 
@@ -1161,7 +1209,8 @@
     /// `point`.
     fn eval_verify_bound(
         &self,
-        tcx: TyCtxt<'tcx>,
+        infcx: &InferCtxt<'_, 'tcx>,
+        param_env: ty::ParamEnv<'tcx>,
         body: &Body<'tcx>,
         generic_ty: Ty<'tcx>,
         lower_bound: RegionVid,
@@ -1170,8 +1219,8 @@
         debug!("eval_verify_bound(lower_bound={:?}, verify_bound={:?})", lower_bound, verify_bound);
 
         match verify_bound {
-            VerifyBound::IfEq(test_ty, verify_bound1) => {
-                self.eval_if_eq(tcx, body, generic_ty, lower_bound, *test_ty, verify_bound1)
+            VerifyBound::IfEq(verify_if_eq_b) => {
+                self.eval_if_eq(infcx, param_env, generic_ty, lower_bound, *verify_if_eq_b)
             }
 
             VerifyBound::IsEmpty => {
@@ -1185,30 +1234,50 @@
             }
 
             VerifyBound::AnyBound(verify_bounds) => verify_bounds.iter().any(|verify_bound| {
-                self.eval_verify_bound(tcx, body, generic_ty, lower_bound, verify_bound)
+                self.eval_verify_bound(
+                    infcx,
+                    param_env,
+                    body,
+                    generic_ty,
+                    lower_bound,
+                    verify_bound,
+                )
             }),
 
             VerifyBound::AllBounds(verify_bounds) => verify_bounds.iter().all(|verify_bound| {
-                self.eval_verify_bound(tcx, body, generic_ty, lower_bound, verify_bound)
+                self.eval_verify_bound(
+                    infcx,
+                    param_env,
+                    body,
+                    generic_ty,
+                    lower_bound,
+                    verify_bound,
+                )
             }),
         }
     }
 
     fn eval_if_eq(
         &self,
-        tcx: TyCtxt<'tcx>,
-        body: &Body<'tcx>,
+        infcx: &InferCtxt<'_, 'tcx>,
+        param_env: ty::ParamEnv<'tcx>,
         generic_ty: Ty<'tcx>,
         lower_bound: RegionVid,
-        test_ty: Ty<'tcx>,
-        verify_bound: &VerifyBound<'tcx>,
+        verify_if_eq_b: ty::Binder<'tcx, VerifyIfEq<'tcx>>,
     ) -> bool {
-        let generic_ty_normalized = self.normalize_to_scc_representatives(tcx, generic_ty);
-        let test_ty_normalized = self.normalize_to_scc_representatives(tcx, test_ty);
-        if generic_ty_normalized == test_ty_normalized {
-            self.eval_verify_bound(tcx, body, generic_ty, lower_bound, verify_bound)
-        } else {
-            false
+        let generic_ty = self.normalize_to_scc_representatives(infcx.tcx, generic_ty);
+        let verify_if_eq_b = self.normalize_to_scc_representatives(infcx.tcx, verify_if_eq_b);
+        match test_type_match::extract_verify_if_eq(
+            infcx.tcx,
+            param_env,
+            &verify_if_eq_b,
+            generic_ty,
+        ) {
+            Some(r) => {
+                let r_vid = self.to_region_vid(r);
+                self.eval_outlives(r_vid, lower_bound)
+            }
+            None => false,
         }
     }
 
@@ -1278,6 +1347,18 @@
         let sub_region_scc = self.constraint_sccs.scc(sub_region);
         let sup_region_scc = self.constraint_sccs.scc(sup_region);
 
+        // If we are checking that `'sup: 'sub`, and `'sub` contains
+        // some placeholder that `'sup` cannot name, then this is only
+        // true if `'sup` outlives static.
+        if !self.universe_compatible(sub_region_scc, sup_region_scc) {
+            debug!(
+                "eval_outlives: sub universe `{sub_region_scc:?}` is not nameable \
+                by super `{sup_region_scc:?}`, promoting to static",
+            );
+
+            return self.eval_outlives(sup_region, self.universal_regions.fr_static);
+        }
+
         // Both the `sub_region` and `sup_region` consist of the union
         // of some number of universal regions (along with the union
         // of various points in the CFG; ignore those points for
@@ -1292,6 +1373,9 @@
             });
 
         if !universal_outlives {
+            debug!(
+                "eval_outlives: returning false because sub region contains a universal region not present in super"
+            );
             return false;
         }
 
@@ -1300,10 +1384,15 @@
 
         if self.universal_regions.is_universal_region(sup_region) {
             // Micro-opt: universal regions contain all points.
+            debug!(
+                "eval_outlives: returning true because super is universal and hence contains all points"
+            );
             return true;
         }
 
-        self.scc_values.contains_points(sup_region_scc, sub_region_scc)
+        let result = self.scc_values.contains_points(sup_region_scc, sub_region_scc);
+        debug!("returning {} because of comparison between points in sup/sub", result);
+        result
     }
 
     /// Once regions have been propagated, this method is used to see
@@ -1693,7 +1782,7 @@
     ///   that cannot be named by `fr1`; in that case, we will require
     ///   that `fr1: 'static` because it is the only way to `fr1: r` to
     ///   be satisfied. (See `add_incompatible_universe`.)
-    crate fn provides_universal_region(
+    pub(crate) fn provides_universal_region(
         &self,
         r: RegionVid,
         fr1: RegionVid,
@@ -1712,7 +1801,7 @@
     /// If `r2` represents a placeholder region, then this returns
     /// `true` if `r1` cannot name that placeholder in its
     /// value; otherwise, returns `false`.
-    crate fn cannot_name_placeholder(&self, r1: RegionVid, r2: RegionVid) -> bool {
+    pub(crate) fn cannot_name_placeholder(&self, r1: RegionVid, r2: RegionVid) -> bool {
         debug!("cannot_name_value_of(r1={:?}, r2={:?})", r1, r2);
 
         match self.definitions[r2].origin {
@@ -1731,7 +1820,7 @@
         }
     }
 
-    crate fn retrieve_closure_constraint_info(
+    pub(crate) fn retrieve_closure_constraint_info(
         &self,
         _body: &Body<'tcx>,
         constraint: &OutlivesConstraint<'tcx>,
@@ -1766,13 +1855,13 @@
     }
 
     /// Finds a good `ObligationCause` to blame for the fact that `fr1` outlives `fr2`.
-    crate fn find_outlives_blame_span(
+    pub(crate) fn find_outlives_blame_span(
         &self,
         body: &Body<'tcx>,
         fr1: RegionVid,
         fr1_origin: NllRegionVariableOrigin,
         fr2: RegionVid,
-    ) -> (ConstraintCategory, ObligationCause<'tcx>) {
+    ) -> (ConstraintCategory<'tcx>, ObligationCause<'tcx>) {
         let BlameConstraint { category, cause, .. } =
             self.best_blame_constraint(body, fr1, fr1_origin, |r| {
                 self.provides_universal_region(r, fr1, fr2)
@@ -1788,7 +1877,7 @@
     ///
     /// Returns: a series of constraints as well as the region `R`
     /// that passed the target test.
-    crate fn find_constraint_paths_between_regions(
+    pub(crate) fn find_constraint_paths_between_regions(
         &self,
         from_region: RegionVid,
         target_test: impl Fn(RegionVid) -> bool,
@@ -1882,7 +1971,7 @@
 
     /// Finds some region R such that `fr1: R` and `R` is live at `elem`.
     #[instrument(skip(self), level = "trace")]
-    crate fn find_sub_region_live_at(&self, fr1: RegionVid, elem: Location) -> RegionVid {
+    pub(crate) fn find_sub_region_live_at(&self, fr1: RegionVid, elem: Location) -> RegionVid {
         trace!(scc = ?self.constraint_sccs.scc(fr1));
         trace!(universe = ?self.scc_universes[self.constraint_sccs.scc(fr1)]);
         self.find_constraint_paths_between_regions(fr1, |r| {
@@ -1919,7 +2008,7 @@
     }
 
     /// Get the region outlived by `longer_fr` and live at `element`.
-    crate fn region_from_element(
+    pub(crate) fn region_from_element(
         &self,
         longer_fr: RegionVid,
         element: &RegionElement,
@@ -1939,17 +2028,17 @@
     }
 
     /// Get the region definition of `r`.
-    crate fn region_definition(&self, r: RegionVid) -> &RegionDefinition<'tcx> {
+    pub(crate) fn region_definition(&self, r: RegionVid) -> &RegionDefinition<'tcx> {
         &self.definitions[r]
     }
 
     /// Check if the SCC of `r` contains `upper`.
-    crate fn upper_bound_in_region_scc(&self, r: RegionVid, upper: RegionVid) -> bool {
+    pub(crate) fn upper_bound_in_region_scc(&self, r: RegionVid, upper: RegionVid) -> bool {
         let r_scc = self.constraint_sccs.scc(r);
         self.scc_values.contains(r_scc, upper)
     }
 
-    crate fn universal_regions(&self) -> &UniversalRegions<'tcx> {
+    pub(crate) fn universal_regions(&self) -> &UniversalRegions<'tcx> {
         self.universal_regions.as_ref()
     }
 
@@ -1959,7 +2048,7 @@
     /// creating a constraint path that forces `R` to outlive
     /// `from_region`, and then finding the best choices within that
     /// path to blame.
-    crate fn best_blame_constraint(
+    pub(crate) fn best_blame_constraint(
         &self,
         body: &Body<'tcx>,
         from_region: RegionVid,
@@ -2171,7 +2260,7 @@
         categorized_path.remove(0)
     }
 
-    crate fn universe_info(&self, universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
+    pub(crate) fn universe_info(&self, universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
         self.universe_causes[&universe].clone()
     }
 }
@@ -2270,7 +2359,7 @@
 
 #[derive(Clone, Debug)]
 pub struct BlameConstraint<'tcx> {
-    pub category: ConstraintCategory,
+    pub category: ConstraintCategory<'tcx>,
     pub from_closure: bool,
     pub cause: ObligationCause<'tcx>,
     pub variance_info: ty::VarianceDiagInfo<'tcx>,
diff --git a/compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs b/compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs
index 056907d..1e6798e 100644
--- a/compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs
+++ b/compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs
@@ -8,7 +8,7 @@
 use std::ops::Range;
 use std::rc::Rc;
 
-crate struct ReverseSccGraph {
+pub(crate) struct ReverseSccGraph {
     graph: VecGraph<ConstraintSccIndex>,
     /// For each SCC, the range of `universal_regions` that use that SCC as
     /// their value.
diff --git a/compiler/rustc_borrowck/src/region_infer/values.rs b/compiler/rustc_borrowck/src/region_infer/values.rs
index 4a70535..c81ef10 100644
--- a/compiler/rustc_borrowck/src/region_infer/values.rs
+++ b/compiler/rustc_borrowck/src/region_infer/values.rs
@@ -10,7 +10,7 @@
 use std::rc::Rc;
 
 /// Maps between a `Location` and a `PointIndex` (and vice versa).
-crate struct RegionValueElements {
+pub(crate) struct RegionValueElements {
     /// For each basic block, how many points are contained within?
     statements_before_block: IndexVec<BasicBlock, usize>,
 
@@ -22,7 +22,7 @@
 }
 
 impl RegionValueElements {
-    crate fn new(body: &Body<'_>) -> Self {
+    pub(crate) fn new(body: &Body<'_>) -> Self {
         let mut num_points = 0;
         let statements_before_block: IndexVec<BasicBlock, usize> = body
             .basic_blocks()
@@ -45,30 +45,30 @@
     }
 
     /// Total number of point indices
-    crate fn num_points(&self) -> usize {
+    pub(crate) fn num_points(&self) -> usize {
         self.num_points
     }
 
     /// Converts a `Location` into a `PointIndex`. O(1).
-    crate fn point_from_location(&self, location: Location) -> PointIndex {
+    pub(crate) fn point_from_location(&self, location: Location) -> PointIndex {
         let Location { block, statement_index } = location;
         let start_index = self.statements_before_block[block];
         PointIndex::new(start_index + statement_index)
     }
 
     /// Converts a `Location` into a `PointIndex`. O(1).
-    crate fn entry_point(&self, block: BasicBlock) -> PointIndex {
+    pub(crate) fn entry_point(&self, block: BasicBlock) -> PointIndex {
         let start_index = self.statements_before_block[block];
         PointIndex::new(start_index)
     }
 
     /// Return the PointIndex for the block start of this index.
-    crate fn to_block_start(&self, index: PointIndex) -> PointIndex {
+    pub(crate) fn to_block_start(&self, index: PointIndex) -> PointIndex {
         PointIndex::new(self.statements_before_block[self.basic_blocks[index]])
     }
 
     /// Converts a `PointIndex` back to a location. O(1).
-    crate fn to_location(&self, index: PointIndex) -> Location {
+    pub(crate) fn to_location(&self, index: PointIndex) -> Location {
         assert!(index.index() < self.num_points);
         let block = self.basic_blocks[index];
         let start_index = self.statements_before_block[block];
@@ -80,7 +80,7 @@
     /// out of range (because they round up to the nearest 2^N number
     /// of bits). Use this function to filter such points out if you
     /// like.
-    crate fn point_in_range(&self, index: PointIndex) -> bool {
+    pub(crate) fn point_in_range(&self, index: PointIndex) -> bool {
         index.index() < self.num_points
     }
 }
@@ -99,7 +99,7 @@
 /// An individual element in a region value -- the value of a
 /// particular region variable consists of a set of these elements.
 #[derive(Debug, Clone)]
-crate enum RegionElement {
+pub(crate) enum RegionElement {
     /// A point in the control-flow graph.
     Location(Location),
 
@@ -114,7 +114,7 @@
 
 /// When we initially compute liveness, we use an interval matrix storing
 /// liveness ranges for each region-vid.
-crate struct LivenessValues<N: Idx> {
+pub(crate) struct LivenessValues<N: Idx> {
     elements: Rc<RegionValueElements>,
     points: SparseIntervalMatrix<N, PointIndex>,
 }
@@ -123,18 +123,18 @@
     /// Creates a new set of "region values" that tracks causal information.
     /// Each of the regions in num_region_variables will be initialized with an
     /// empty set of points and no causal information.
-    crate fn new(elements: Rc<RegionValueElements>) -> Self {
+    pub(crate) fn new(elements: Rc<RegionValueElements>) -> Self {
         Self { points: SparseIntervalMatrix::new(elements.num_points), elements }
     }
 
     /// Iterate through each region that has a value in this set.
-    crate fn rows(&self) -> impl Iterator<Item = N> {
+    pub(crate) fn rows(&self) -> impl Iterator<Item = N> {
         self.points.rows()
     }
 
     /// Adds the given element to the value for the given region. Returns whether
     /// the element is newly added (i.e., was not already present).
-    crate fn add_element(&mut self, row: N, location: Location) -> bool {
+    pub(crate) fn add_element(&mut self, row: N, location: Location) -> bool {
         debug!("LivenessValues::add(r={:?}, location={:?})", row, location);
         let index = self.elements.point_from_location(location);
         self.points.insert(row, index)
@@ -142,24 +142,24 @@
 
     /// Adds all the elements in the given bit array into the given
     /// region. Returns whether any of them are newly added.
-    crate fn add_elements(&mut self, row: N, locations: &IntervalSet<PointIndex>) -> bool {
+    pub(crate) fn add_elements(&mut self, row: N, locations: &IntervalSet<PointIndex>) -> bool {
         debug!("LivenessValues::add_elements(row={:?}, locations={:?})", row, locations);
         self.points.union_row(row, locations)
     }
 
     /// Adds all the control-flow points to the values for `r`.
-    crate fn add_all_points(&mut self, row: N) {
+    pub(crate) fn add_all_points(&mut self, row: N) {
         self.points.insert_all_into_row(row);
     }
 
     /// Returns `true` if the region `r` contains the given element.
-    crate fn contains(&self, row: N, location: Location) -> bool {
+    pub(crate) fn contains(&self, row: N, location: Location) -> bool {
         let index = self.elements.point_from_location(location);
         self.points.row(row).map_or(false, |r| r.contains(index))
     }
 
     /// Returns an iterator of all the elements contained by the region `r`
-    crate fn get_elements(&self, row: N) -> impl Iterator<Item = Location> + '_ {
+    pub(crate) fn get_elements(&self, row: N) -> impl Iterator<Item = Location> + '_ {
         self.points
             .row(row)
             .into_iter()
@@ -169,7 +169,7 @@
     }
 
     /// Returns a "pretty" string value of the region. Meant for debugging.
-    crate fn region_value_str(&self, r: N) -> String {
+    pub(crate) fn region_value_str(&self, r: N) -> String {
         region_value_str(self.get_elements(r).map(RegionElement::Location))
     }
 }
@@ -178,25 +178,28 @@
 /// rustc to the internal `PlaceholderIndex` values that are used in
 /// NLL.
 #[derive(Default)]
-crate struct PlaceholderIndices {
+pub(crate) struct PlaceholderIndices {
     indices: FxIndexSet<ty::PlaceholderRegion>,
 }
 
 impl PlaceholderIndices {
-    crate fn insert(&mut self, placeholder: ty::PlaceholderRegion) -> PlaceholderIndex {
+    pub(crate) fn insert(&mut self, placeholder: ty::PlaceholderRegion) -> PlaceholderIndex {
         let (index, _) = self.indices.insert_full(placeholder);
         index.into()
     }
 
-    crate fn lookup_index(&self, placeholder: ty::PlaceholderRegion) -> PlaceholderIndex {
+    pub(crate) fn lookup_index(&self, placeholder: ty::PlaceholderRegion) -> PlaceholderIndex {
         self.indices.get_index_of(&placeholder).unwrap().into()
     }
 
-    crate fn lookup_placeholder(&self, placeholder: PlaceholderIndex) -> ty::PlaceholderRegion {
+    pub(crate) fn lookup_placeholder(
+        &self,
+        placeholder: PlaceholderIndex,
+    ) -> ty::PlaceholderRegion {
         self.indices[placeholder.index()]
     }
 
-    crate fn len(&self) -> usize {
+    pub(crate) fn len(&self) -> usize {
         self.indices.len()
     }
 }
@@ -220,7 +223,7 @@
 /// because (since it is returned) it must live for at least `'a`. But
 /// it would also contain various points from within the function.
 #[derive(Clone)]
-crate struct RegionValues<N: Idx> {
+pub(crate) struct RegionValues<N: Idx> {
     elements: Rc<RegionValueElements>,
     placeholder_indices: Rc<PlaceholderIndices>,
     points: SparseIntervalMatrix<N, PointIndex>,
@@ -235,7 +238,7 @@
     /// Creates a new set of "region values" that tracks causal information.
     /// Each of the regions in num_region_variables will be initialized with an
     /// empty set of points and no causal information.
-    crate fn new(
+    pub(crate) fn new(
         elements: &Rc<RegionValueElements>,
         num_universal_regions: usize,
         placeholder_indices: &Rc<PlaceholderIndices>,
@@ -252,33 +255,33 @@
 
     /// Adds the given element to the value for the given region. Returns whether
     /// the element is newly added (i.e., was not already present).
-    crate fn add_element(&mut self, r: N, elem: impl ToElementIndex) -> bool {
+    pub(crate) fn add_element(&mut self, r: N, elem: impl ToElementIndex) -> bool {
         debug!("add(r={:?}, elem={:?})", r, elem);
         elem.add_to_row(self, r)
     }
 
     /// Adds all the control-flow points to the values for `r`.
-    crate fn add_all_points(&mut self, r: N) {
+    pub(crate) fn add_all_points(&mut self, r: N) {
         self.points.insert_all_into_row(r);
     }
 
     /// Adds all elements in `r_from` to `r_to` (because e.g., `r_to:
     /// r_from`).
-    crate fn add_region(&mut self, r_to: N, r_from: N) -> bool {
+    pub(crate) fn add_region(&mut self, r_to: N, r_from: N) -> bool {
         self.points.union_rows(r_from, r_to)
             | self.free_regions.union_rows(r_from, r_to)
             | self.placeholders.union_rows(r_from, r_to)
     }
 
     /// Returns `true` if the region `r` contains the given element.
-    crate fn contains(&self, r: N, elem: impl ToElementIndex) -> bool {
+    pub(crate) fn contains(&self, r: N, elem: impl ToElementIndex) -> bool {
         elem.contained_in_row(self, r)
     }
 
     /// `self[to] |= values[from]`, essentially: that is, take all the
     /// elements for the region `from` from `values` and add them to
     /// the region `to` in `self`.
-    crate fn merge_liveness<M: Idx>(&mut self, to: N, from: M, values: &LivenessValues<M>) {
+    pub(crate) fn merge_liveness<M: Idx>(&mut self, to: N, from: M, values: &LivenessValues<M>) {
         if let Some(set) = values.points.row(from) {
             self.points.union_row(to, set);
         }
@@ -286,7 +289,7 @@
 
     /// Returns `true` if `sup_region` contains all the CFG points that
     /// `sub_region` contains. Ignores universal regions.
-    crate fn contains_points(&self, sup_region: N, sub_region: N) -> bool {
+    pub(crate) fn contains_points(&self, sup_region: N, sub_region: N) -> bool {
         if let Some(sub_row) = self.points.row(sub_region) {
             if let Some(sup_row) = self.points.row(sup_region) {
                 sup_row.superset(sub_row)
@@ -301,7 +304,7 @@
     }
 
     /// Returns the locations contained within a given region `r`.
-    crate fn locations_outlived_by<'a>(&'a self, r: N) -> impl Iterator<Item = Location> + 'a {
+    pub(crate) fn locations_outlived_by<'a>(&'a self, r: N) -> impl Iterator<Item = Location> + 'a {
         self.points.row(r).into_iter().flat_map(move |set| {
             set.iter()
                 .take_while(move |&p| self.elements.point_in_range(p))
@@ -310,7 +313,7 @@
     }
 
     /// Returns just the universal regions that are contained in a given region's value.
-    crate fn universal_regions_outlived_by<'a>(
+    pub(crate) fn universal_regions_outlived_by<'a>(
         &'a self,
         r: N,
     ) -> impl Iterator<Item = RegionVid> + 'a {
@@ -318,7 +321,7 @@
     }
 
     /// Returns all the elements contained in a given region's value.
-    crate fn placeholders_contained_in<'a>(
+    pub(crate) fn placeholders_contained_in<'a>(
         &'a self,
         r: N,
     ) -> impl Iterator<Item = ty::PlaceholderRegion> + 'a {
@@ -330,7 +333,10 @@
     }
 
     /// Returns all the elements contained in a given region's value.
-    crate fn elements_contained_in<'a>(&'a self, r: N) -> impl Iterator<Item = RegionElement> + 'a {
+    pub(crate) fn elements_contained_in<'a>(
+        &'a self,
+        r: N,
+    ) -> impl Iterator<Item = RegionElement> + 'a {
         let points_iter = self.locations_outlived_by(r).map(RegionElement::Location);
 
         let free_regions_iter =
@@ -343,12 +349,12 @@
     }
 
     /// Returns a "pretty" string value of the region. Meant for debugging.
-    crate fn region_value_str(&self, r: N) -> String {
+    pub(crate) fn region_value_str(&self, r: N) -> String {
         region_value_str(self.elements_contained_in(r))
     }
 }
 
-crate trait ToElementIndex: Debug + Copy {
+pub(crate) trait ToElementIndex: Debug + Copy {
     fn add_to_row<N: Idx>(self, values: &mut RegionValues<N>, row: N) -> bool;
 
     fn contained_in_row<N: Idx>(self, values: &RegionValues<N>, row: N) -> bool;
@@ -388,7 +394,7 @@
     }
 }
 
-crate fn location_set_str(
+pub(crate) fn location_set_str(
     elements: &RegionValueElements,
     points: impl IntoIterator<Item = PointIndex>,
 ) -> String {
diff --git a/compiler/rustc_borrowck/src/type_check/canonical.rs b/compiler/rustc_borrowck/src/type_check/canonical.rs
index 3856b7f..55c0bf0 100644
--- a/compiler/rustc_borrowck/src/type_check/canonical.rs
+++ b/compiler/rustc_borrowck/src/type_check/canonical.rs
@@ -28,7 +28,7 @@
     pub(super) fn fully_perform_op<R, Op>(
         &mut self,
         locations: Locations,
-        category: ConstraintCategory,
+        category: ConstraintCategory<'tcx>,
         op: Op,
     ) -> Fallible<R>
     where
@@ -83,11 +83,12 @@
         instantiated
     }
 
+    #[instrument(skip(self), level = "debug")]
     pub(super) fn prove_trait_ref(
         &mut self,
         trait_ref: ty::TraitRef<'tcx>,
         locations: Locations,
-        category: ConstraintCategory,
+        category: ConstraintCategory<'tcx>,
     ) {
         self.prove_predicates(
             Some(ty::Binder::dummy(ty::PredicateKind::Trait(ty::TraitPredicate {
@@ -113,6 +114,7 @@
             .into_iter()
             .zip(instantiated_predicates.spans.into_iter())
         {
+            debug!(?predicate);
             let predicate = self.normalize(predicate, locations);
             self.prove_predicate(predicate, locations, ConstraintCategory::Predicate(span));
         }
@@ -122,7 +124,7 @@
         &mut self,
         predicates: impl IntoIterator<Item = impl ToPredicate<'tcx>>,
         locations: Locations,
-        category: ConstraintCategory,
+        category: ConstraintCategory<'tcx>,
     ) {
         for predicate in predicates {
             let predicate = predicate.to_predicate(self.tcx());
@@ -137,7 +139,7 @@
         &mut self,
         predicate: ty::Predicate<'tcx>,
         locations: Locations,
-        category: ConstraintCategory,
+        category: ConstraintCategory<'tcx>,
     ) {
         let param_env = self.param_env;
         self.fully_perform_op(
diff --git a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
index 21190a8..3c9e387 100644
--- a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
+++ b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
@@ -18,7 +18,7 @@
     universal_regions::UniversalRegions,
 };
 
-crate struct ConstraintConversion<'a, 'tcx> {
+pub(crate) struct ConstraintConversion<'a, 'tcx> {
     infcx: &'a InferCtxt<'a, 'tcx>,
     tcx: TyCtxt<'tcx>,
     universal_regions: &'a UniversalRegions<'tcx>,
@@ -27,12 +27,12 @@
     param_env: ty::ParamEnv<'tcx>,
     locations: Locations,
     span: Span,
-    category: ConstraintCategory,
+    category: ConstraintCategory<'tcx>,
     constraints: &'a mut MirTypeckRegionConstraints<'tcx>,
 }
 
 impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
-    crate fn new(
+    pub(crate) fn new(
         infcx: &'a InferCtxt<'a, 'tcx>,
         universal_regions: &'a UniversalRegions<'tcx>,
         region_bound_pairs: &'a RegionBoundPairs<'tcx>,
@@ -40,7 +40,7 @@
         param_env: ty::ParamEnv<'tcx>,
         locations: Locations,
         span: Span,
-        category: ConstraintCategory,
+        category: ConstraintCategory<'tcx>,
         constraints: &'a mut MirTypeckRegionConstraints<'tcx>,
     ) -> Self {
         Self {
diff --git a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
index f08f2e1..8133073 100644
--- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
+++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
@@ -19,7 +19,7 @@
 };
 
 #[derive(Debug)]
-crate struct UniversalRegionRelations<'tcx> {
+pub(crate) struct UniversalRegionRelations<'tcx> {
     universal_regions: Rc<UniversalRegions<'tcx>>,
 
     /// Stores the outlives relations that are known to hold from the
@@ -52,13 +52,13 @@
 /// then the output type as the last element.
 type NormalizedInputsAndOutput<'tcx> = Vec<Ty<'tcx>>;
 
-crate struct CreateResult<'tcx> {
-    crate universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,
-    crate region_bound_pairs: RegionBoundPairs<'tcx>,
-    crate normalized_inputs_and_output: NormalizedInputsAndOutput<'tcx>,
+pub(crate) struct CreateResult<'tcx> {
+    pub(crate) universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,
+    pub(crate) region_bound_pairs: RegionBoundPairs<'tcx>,
+    pub(crate) normalized_inputs_and_output: NormalizedInputsAndOutput<'tcx>,
 }
 
-crate fn create<'tcx>(
+pub(crate) fn create<'tcx>(
     infcx: &InferCtxt<'_, 'tcx>,
     param_env: ty::ParamEnv<'tcx>,
     implicit_region_bound: Option<ty::Region<'tcx>>,
@@ -96,7 +96,7 @@
     ///
     /// (See `TransitiveRelation::postdom_upper_bound` for details on
     /// the postdominating upper bound in general.)
-    crate fn postdom_upper_bound(&self, fr1: RegionVid, fr2: RegionVid) -> RegionVid {
+    pub(crate) fn postdom_upper_bound(&self, fr1: RegionVid, fr2: RegionVid) -> RegionVid {
         assert!(self.universal_regions.is_universal_region(fr1));
         assert!(self.universal_regions.is_universal_region(fr2));
         self.inverse_outlives
@@ -109,7 +109,7 @@
     /// outlives `fr` and (b) is not local.
     ///
     /// (*) If there are multiple competing choices, we return all of them.
-    crate fn non_local_upper_bounds<'a>(&'a self, fr: RegionVid) -> Vec<RegionVid> {
+    pub(crate) fn non_local_upper_bounds<'a>(&'a self, fr: RegionVid) -> Vec<RegionVid> {
         debug!("non_local_upper_bound(fr={:?})", fr);
         let res = self.non_local_bounds(&self.inverse_outlives, fr);
         assert!(!res.is_empty(), "can't find an upper bound!?");
@@ -118,7 +118,7 @@
 
     /// Returns the "postdominating" bound of the set of
     /// `non_local_upper_bounds` for the given region.
-    crate fn non_local_upper_bound(&self, fr: RegionVid) -> RegionVid {
+    pub(crate) fn non_local_upper_bound(&self, fr: RegionVid) -> RegionVid {
         let upper_bounds = self.non_local_upper_bounds(fr);
 
         // In case we find more than one, reduce to one for
@@ -147,7 +147,7 @@
     ///
     /// (*) If there are multiple competing choices, we pick the "postdominating"
     /// one. See `TransitiveRelation::postdom_upper_bound` for details.
-    crate fn non_local_lower_bound(&self, fr: RegionVid) -> Option<RegionVid> {
+    pub(crate) fn non_local_lower_bound(&self, fr: RegionVid) -> Option<RegionVid> {
         debug!("non_local_lower_bound(fr={:?})", fr);
         let lower_bounds = self.non_local_bounds(&self.outlives, fr);
 
@@ -203,18 +203,18 @@
     /// Returns `true` if fr1 is known to outlive fr2.
     ///
     /// This will only ever be true for universally quantified regions.
-    crate fn outlives(&self, fr1: RegionVid, fr2: RegionVid) -> bool {
+    pub(crate) fn outlives(&self, fr1: RegionVid, fr2: RegionVid) -> bool {
         self.outlives.contains(fr1, fr2)
     }
 
     /// Returns a vector of free regions `x` such that `fr1: x` is
     /// known to hold.
-    crate fn regions_outlived_by(&self, fr1: RegionVid) -> Vec<RegionVid> {
+    pub(crate) fn regions_outlived_by(&self, fr1: RegionVid) -> Vec<RegionVid> {
         self.outlives.reachable_from(fr1)
     }
 
     /// Returns the _non-transitive_ set of known `outlives` constraints between free regions.
-    crate fn known_outlives(&self) -> impl Iterator<Item = (RegionVid, RegionVid)> + '_ {
+    pub(crate) fn known_outlives(&self) -> impl Iterator<Item = (RegionVid, RegionVid)> + '_ {
         self.outlives.base_edges()
     }
 }
@@ -232,7 +232,7 @@
 }
 
 impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
-    crate fn create(mut self) -> CreateResult<'tcx> {
+    pub(crate) fn create(mut self) -> CreateResult<'tcx> {
         let unnormalized_input_output_tys = self
             .universal_regions
             .unnormalized_input_tys
@@ -334,8 +334,8 @@
     /// either the return type of the MIR or one of its arguments. At
     /// the same time, compute and add any implied bounds that come
     /// from this local.
+    #[instrument(level = "debug", skip(self))]
     fn add_implied_bounds(&mut self, ty: Ty<'tcx>) -> Option<Rc<QueryRegionConstraints<'tcx>>> {
-        debug!("add_implied_bounds(ty={:?})", ty);
         let TypeOpOutput { output: bounds, constraints, .. } = self
             .param_env
             .and(type_op::implied_outlives_bounds::ImpliedOutlivesBounds { ty })
diff --git a/compiler/rustc_borrowck/src/type_check/input_output.rs b/compiler/rustc_borrowck/src/type_check/input_output.rs
index e6f9964..2259a59 100644
--- a/compiler/rustc_borrowck/src/type_check/input_output.rs
+++ b/compiler/rustc_borrowck/src/type_check/input_output.rs
@@ -60,13 +60,11 @@
                     // Replace the bound items in the fn sig with fresh
                     // variables, so that they represent the view from
                     // "inside" the closure.
-                    self.infcx
-                        .replace_bound_vars_with_fresh_vars(
-                            body.span,
-                            LateBoundRegionConversionTime::FnCall,
-                            poly_sig,
-                        )
-                        .0
+                    self.infcx.replace_bound_vars_with_fresh_vars(
+                        body.span,
+                        LateBoundRegionConversionTime::FnCall,
+                        poly_sig,
+                    )
                 },
             );
         }
diff --git a/compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs b/compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs
index dd23683..b88f6e6 100644
--- a/compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs
+++ b/compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs
@@ -18,7 +18,7 @@
 /// (and code simplicity) was favored. The rationale is that we only keep
 /// a small number of `IndexVec`s throughout the entire analysis while, in
 /// contrast, we're accessing each `Local` *many* times.
-crate struct LocalUseMap {
+pub(crate) struct LocalUseMap {
     /// Head of a linked list of **definitions** of each variable --
     /// definition in this context means assignment, e.g., `x` is
     /// defined in `x = y` but not `y`; that first def is the head of
@@ -58,7 +58,11 @@
 }
 
 impl LocalUseMap {
-    crate fn build(live_locals: &[Local], elements: &RegionValueElements, body: &Body<'_>) -> Self {
+    pub(crate) fn build(
+        live_locals: &[Local],
+        elements: &RegionValueElements,
+        body: &Body<'_>,
+    ) -> Self {
         let nones = IndexVec::from_elem_n(None, body.local_decls.len());
         let mut local_use_map = LocalUseMap {
             first_def_at: nones.clone(),
@@ -81,17 +85,17 @@
         local_use_map
     }
 
-    crate fn defs(&self, local: Local) -> impl Iterator<Item = PointIndex> + '_ {
+    pub(crate) fn defs(&self, local: Local) -> impl Iterator<Item = PointIndex> + '_ {
         vll::iter(self.first_def_at[local], &self.appearances)
             .map(move |aa| self.appearances[aa].point_index)
     }
 
-    crate fn uses(&self, local: Local) -> impl Iterator<Item = PointIndex> + '_ {
+    pub(crate) fn uses(&self, local: Local) -> impl Iterator<Item = PointIndex> + '_ {
         vll::iter(self.first_use_at[local], &self.appearances)
             .map(move |aa| self.appearances[aa].point_index)
     }
 
-    crate fn drops(&self, local: Local) -> impl Iterator<Item = PointIndex> + '_ {
+    pub(crate) fn drops(&self, local: Local) -> impl Iterator<Item = PointIndex> + '_ {
         vll::iter(self.first_drop_at[local], &self.appearances)
             .map(move |aa| self.appearances[aa].point_index)
     }
diff --git a/compiler/rustc_borrowck/src/type_check/liveness/polonius.rs b/compiler/rustc_borrowck/src/type_check/liveness/polonius.rs
index ee067c4..8070f35 100644
--- a/compiler/rustc_borrowck/src/type_check/liveness/polonius.rs
+++ b/compiler/rustc_borrowck/src/type_check/liveness/polonius.rs
@@ -10,17 +10,17 @@
 type VarPointRelation = Vec<(Local, LocationIndex)>;
 type PathPointRelation = Vec<(MovePathIndex, LocationIndex)>;
 
-struct UseFactsExtractor<'me> {
+struct UseFactsExtractor<'me, 'tcx> {
     var_defined_at: &'me mut VarPointRelation,
     var_used_at: &'me mut VarPointRelation,
     location_table: &'me LocationTable,
     var_dropped_at: &'me mut VarPointRelation,
-    move_data: &'me MoveData<'me>,
+    move_data: &'me MoveData<'tcx>,
     path_accessed_at_base: &'me mut PathPointRelation,
 }
 
 // A Visitor to walk through the MIR and extract point-wise facts
-impl UseFactsExtractor<'_> {
+impl UseFactsExtractor<'_, '_> {
     fn location_to_index(&self, location: Location) -> LocationIndex {
         self.location_table.mid_index(location)
     }
@@ -53,7 +53,7 @@
     }
 }
 
-impl Visitor<'_> for UseFactsExtractor<'_> {
+impl<'a, 'tcx> Visitor<'tcx> for UseFactsExtractor<'a, 'tcx> {
     fn visit_local(&mut self, &local: &Local, context: PlaceContext, location: Location) {
         match def_use::categorize(context) {
             Some(DefUse::Def) => self.insert_def(local, location),
@@ -63,7 +63,7 @@
         }
     }
 
-    fn visit_place(&mut self, place: &Place<'_>, context: PlaceContext, location: Location) {
+    fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, location: Location) {
         self.super_place(place, context, location);
         match context {
             PlaceContext::NonMutatingUse(_) => {
@@ -82,11 +82,11 @@
     }
 }
 
-pub(super) fn populate_access_facts<'tcx>(
-    typeck: &mut TypeChecker<'_, 'tcx>,
+pub(super) fn populate_access_facts<'a, 'tcx>(
+    typeck: &mut TypeChecker<'a, 'tcx>,
     body: &Body<'tcx>,
     location_table: &LocationTable,
-    move_data: &MoveData<'_>,
+    move_data: &MoveData<'tcx>,
     dropped_at: &mut Vec<(Local, Location)>,
 ) {
     debug!("populate_access_facts()");
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index 4b905c2..355254f 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -20,7 +20,7 @@
 use rustc_infer::infer::region_constraints::RegionConstraintData;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_infer::infer::{
-    InferCtxt, InferOk, LateBoundRegionConversionTime, NllRegionVariableOrigin,
+    InferCtxt, InferOk, LateBoundRegion, LateBoundRegionConversionTime, NllRegionVariableOrigin,
 };
 use rustc_middle::mir::tcx::PlaceTy;
 use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor};
@@ -94,7 +94,7 @@
 mod constraint_conversion;
 pub mod free_region_relations;
 mod input_output;
-crate mod liveness;
+pub(crate) mod liveness;
 mod relate_tys;
 
 /// Type checks the given `mir` in the context of the inference
@@ -162,6 +162,8 @@
         &mut constraints,
     );
 
+    debug!(?normalized_inputs_and_output);
+
     for u in ty::UniverseIndex::ROOT..infcx.universe() {
         let info = UniverseInfo::other();
         constraints.universe_causes.insert(u, info);
@@ -185,6 +187,7 @@
         implicit_region_bound,
         &mut borrowck_context,
         |mut cx| {
+            debug!("inside extra closure of type_check_internal");
             cx.equate_inputs_and_outputs(&body, universal_regions, &normalized_inputs_and_output);
             liveness::generate(
                 &mut cx,
@@ -257,6 +260,7 @@
     borrowck_context: &'a mut BorrowCheckContext<'a, 'tcx>,
     extra: impl FnOnce(TypeChecker<'a, 'tcx>) -> R,
 ) -> R {
+    debug!("body: {:#?}", body);
     let mut checker = TypeChecker::new(
         infcx,
         body,
@@ -353,12 +357,20 @@
                 .add_element(live_region_vid, location);
         });
 
+        // HACK(compiler-errors): Constants that are gathered into Body.required_consts
+        // have their locations erased...
+        let locations = if location != Location::START {
+            location.to_locations()
+        } else {
+            Locations::All(constant.span)
+        };
+
         if let Some(annotation_index) = constant.user_ty {
             if let Err(terr) = self.cx.relate_type_and_user_type(
                 constant.literal.ty(),
                 ty::Variance::Invariant,
                 &UserTypeProjection { base: annotation_index, projs: vec![] },
-                location.to_locations(),
+                locations,
                 ConstraintCategory::Boring,
             ) {
                 let annotation = &self.cx.user_type_annotations[annotation_index];
@@ -374,7 +386,7 @@
         } else {
             let tcx = self.tcx();
             let maybe_uneval = match constant.literal {
-                ConstantKind::Ty(ct) => match ct.val() {
+                ConstantKind::Ty(ct) => match ct.kind() {
                     ty::ConstKind::Unevaluated(uv) => Some(uv),
                     _ => None,
                 },
@@ -386,12 +398,9 @@
                                      promoted: &Body<'tcx>,
                                      ty,
                                      san_ty| {
-                        if let Err(terr) = verifier.cx.eq_types(
-                            ty,
-                            san_ty,
-                            location.to_locations(),
-                            ConstraintCategory::Boring,
-                        ) {
+                        if let Err(terr) =
+                            verifier.cx.eq_types(ty, san_ty, locations, ConstraintCategory::Boring)
+                        {
                             span_mirbug!(
                                 verifier,
                                 promoted,
@@ -412,7 +421,7 @@
                     }
                 } else {
                     if let Err(terr) = self.cx.fully_perform_op(
-                        location.to_locations(),
+                        locations,
                         ConstraintCategory::Boring,
                         self.cx.param_env.and(type_op::ascribe_user_type::AscribeUserType::new(
                             constant.literal.ty(),
@@ -431,7 +440,6 @@
                 }
             } else if let Some(static_def_id) = constant.check_static_ptr(tcx) {
                 let unnormalized_ty = tcx.type_of(static_def_id);
-                let locations = location.to_locations();
                 let normalized_ty = self.cx.normalize(unnormalized_ty, locations);
                 let literal_ty = constant.literal.ty().builtin_deref(true).unwrap().ty;
 
@@ -450,7 +458,7 @@
                 self.cx.normalize_and_prove_instantiated_predicates(
                     def_id,
                     instantiated_predicates,
-                    location.to_locations(),
+                    locations,
                 );
             }
         }
@@ -897,28 +905,29 @@
     upvars: &'a [Upvar<'tcx>],
 }
 
-crate struct MirTypeckResults<'tcx> {
-    crate constraints: MirTypeckRegionConstraints<'tcx>,
-    crate universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,
-    crate opaque_type_values: VecMap<OpaqueTypeKey<'tcx>, (OpaqueHiddenType<'tcx>, OpaqueTyOrigin)>,
+pub(crate) struct MirTypeckResults<'tcx> {
+    pub(crate) constraints: MirTypeckRegionConstraints<'tcx>,
+    pub(crate) universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,
+    pub(crate) opaque_type_values:
+        VecMap<OpaqueTypeKey<'tcx>, (OpaqueHiddenType<'tcx>, OpaqueTyOrigin)>,
 }
 
 /// A collection of region constraints that must be satisfied for the
 /// program to be considered well-typed.
-crate struct MirTypeckRegionConstraints<'tcx> {
+pub(crate) struct MirTypeckRegionConstraints<'tcx> {
     /// Maps from a `ty::Placeholder` to the corresponding
     /// `PlaceholderIndex` bit that we will use for it.
     ///
     /// To keep everything in sync, do not insert this set
     /// directly. Instead, use the `placeholder_region` helper.
-    crate placeholder_indices: PlaceholderIndices,
+    pub(crate) placeholder_indices: PlaceholderIndices,
 
     /// Each time we add a placeholder to `placeholder_indices`, we
     /// also create a corresponding "representative" region vid for
     /// that wraps it. This vector tracks those. This way, when we
     /// convert the same `ty::RePlaceholder(p)` twice, we can map to
     /// the same underlying `RegionVid`.
-    crate placeholder_index_to_region: IndexVec<PlaceholderIndex, ty::Region<'tcx>>,
+    pub(crate) placeholder_index_to_region: IndexVec<PlaceholderIndex, ty::Region<'tcx>>,
 
     /// In general, the type-checker is not responsible for enforcing
     /// liveness constraints; this job falls to the region inferencer,
@@ -927,18 +936,18 @@
     /// not otherwise appear in the MIR -- in particular, the
     /// late-bound regions that it instantiates at call-sites -- and
     /// hence it must report on their liveness constraints.
-    crate liveness_constraints: LivenessValues<RegionVid>,
+    pub(crate) liveness_constraints: LivenessValues<RegionVid>,
 
-    crate outlives_constraints: OutlivesConstraintSet<'tcx>,
+    pub(crate) outlives_constraints: OutlivesConstraintSet<'tcx>,
 
-    crate member_constraints: MemberConstraintSet<'tcx, RegionVid>,
+    pub(crate) member_constraints: MemberConstraintSet<'tcx, RegionVid>,
 
-    crate closure_bounds_mapping:
-        FxHashMap<Location, FxHashMap<(RegionVid, RegionVid), (ConstraintCategory, Span)>>,
+    pub(crate) closure_bounds_mapping:
+        FxHashMap<Location, FxHashMap<(RegionVid, RegionVid), (ConstraintCategory<'tcx>, Span)>>,
 
-    crate universe_causes: FxHashMap<ty::UniverseIndex, UniverseInfo<'tcx>>,
+    pub(crate) universe_causes: FxHashMap<ty::UniverseIndex, UniverseInfo<'tcx>>,
 
-    crate type_tests: Vec<TypeTest<'tcx>>,
+    pub(crate) type_tests: Vec<TypeTest<'tcx>>,
 }
 
 impl<'tcx> MirTypeckRegionConstraints<'tcx> {
@@ -1124,7 +1133,7 @@
     fn push_region_constraints(
         &mut self,
         locations: Locations,
-        category: ConstraintCategory,
+        category: ConstraintCategory<'tcx>,
         data: &QueryRegionConstraints<'tcx>,
     ) {
         debug!("constraints generated: {:#?}", data);
@@ -1149,7 +1158,7 @@
         sub: Ty<'tcx>,
         sup: Ty<'tcx>,
         locations: Locations,
-        category: ConstraintCategory,
+        category: ConstraintCategory<'tcx>,
     ) -> Fallible<()> {
         // Use this order of parameters because the sup type is usually the
         // "expected" type in diagnostics.
@@ -1162,7 +1171,7 @@
         expected: Ty<'tcx>,
         found: Ty<'tcx>,
         locations: Locations,
-        category: ConstraintCategory,
+        category: ConstraintCategory<'tcx>,
     ) -> Fallible<()> {
         self.relate_types(expected, ty::Variance::Invariant, found, locations, category)
     }
@@ -1174,7 +1183,7 @@
         v: ty::Variance,
         user_ty: &UserTypeProjection,
         locations: Locations,
-        category: ConstraintCategory,
+        category: ConstraintCategory<'tcx>,
     ) -> Fallible<()> {
         let annotated_type = self.user_type_annotations[user_ty.base].inferred_ty;
         let mut curr_projected_ty = PlaceTy::from_ty(annotated_type);
@@ -1211,6 +1220,7 @@
     #[instrument(skip(self, body, location), level = "debug")]
     fn check_stmt(&mut self, body: &Body<'tcx>, stmt: &Statement<'tcx>, location: Location) {
         let tcx = self.tcx();
+        debug!("stmt kind: {:?}", stmt.kind);
         match stmt.kind {
             StatementKind::Assign(box (ref place, ref rv)) => {
                 // Assignments to temporaries are not "interesting";
@@ -1250,9 +1260,13 @@
                 );
 
                 let place_ty = place.ty(body, tcx).ty;
+                debug!(?place_ty);
                 let place_ty = self.normalize(place_ty, location);
+                debug!("place_ty normalized: {:?}", place_ty);
                 let rv_ty = rv.ty(body, tcx);
+                debug!(?rv_ty);
                 let rv_ty = self.normalize(rv_ty, location);
+                debug!("normalized rv_ty: {:?}", rv_ty);
                 if let Err(terr) =
                     self.sub_types(rv_ty, place_ty, location.to_locations(), category)
                 {
@@ -1346,6 +1360,7 @@
         term_location: Location,
     ) {
         let tcx = self.tcx();
+        debug!("terminator kind: {:?}", term.kind);
         match term.kind {
             TerminatorKind::Goto { .. }
             | TerminatorKind::Resume
@@ -1402,14 +1417,22 @@
                 }
                 // FIXME: check the values
             }
-            TerminatorKind::Call { ref func, ref args, ref destination, from_hir_call, .. } => {
+            TerminatorKind::Call {
+                ref func,
+                ref args,
+                ref destination,
+                from_hir_call,
+                target,
+                ..
+            } => {
                 self.check_operand(func, term_location);
                 for arg in args {
                     self.check_operand(arg, term_location);
                 }
 
                 let func_ty = func.ty(body, tcx);
-                debug!("check_terminator: call, func_ty={:?}", func_ty);
+                debug!("func_ty.kind: {:?}", func_ty.kind());
+
                 let sig = match func_ty.kind() {
                     ty::FnDef(..) | ty::FnPtr(_) => func_ty.fn_sig(tcx),
                     _ => {
@@ -1417,13 +1440,16 @@
                         return;
                     }
                 };
-                let (sig, map) = self.infcx.replace_bound_vars_with_fresh_vars(
-                    term.source_info.span,
-                    LateBoundRegionConversionTime::FnCall,
-                    sig,
-                );
+                let (sig, map) = tcx.replace_late_bound_regions(sig, |br| {
+                    self.infcx.next_region_var(LateBoundRegion(
+                        term.source_info.span,
+                        br.kind,
+                        LateBoundRegionConversionTime::FnCall,
+                    ))
+                });
+                debug!(?sig);
                 let sig = self.normalize(sig, term_location);
-                self.check_call_dest(body, term, &sig, destination, term_location);
+                self.check_call_dest(body, term, &sig, *destination, target, term_location);
 
                 self.prove_predicates(
                     sig.inputs_and_output
@@ -1501,15 +1527,16 @@
         body: &Body<'tcx>,
         term: &Terminator<'tcx>,
         sig: &ty::FnSig<'tcx>,
-        destination: &Option<(Place<'tcx>, BasicBlock)>,
+        destination: Place<'tcx>,
+        target: Option<BasicBlock>,
         term_location: Location,
     ) {
         let tcx = self.tcx();
-        match *destination {
-            Some((ref dest, _target_block)) => {
-                let dest_ty = dest.ty(body, tcx).ty;
+        match target {
+            Some(_) => {
+                let dest_ty = destination.ty(body, tcx).ty;
                 let dest_ty = self.normalize(dest_ty, term_location);
-                let category = match dest.as_local() {
+                let category = match destination.as_local() {
                     Some(RETURN_PLACE) => {
                         if let BorrowCheckContext {
                             universal_regions:
@@ -1581,11 +1608,20 @@
         if args.len() < sig.inputs().len() || (args.len() > sig.inputs().len() && !sig.c_variadic) {
             span_mirbug!(self, term, "call to {:?} with wrong # of args", sig);
         }
+
+        let func_ty = if let TerminatorKind::Call { func, .. } = &term.kind {
+            Some(func.ty(body, self.infcx.tcx))
+        } else {
+            None
+        };
+        debug!(?func_ty);
+
         for (n, (fn_arg, op_arg)) in iter::zip(sig.inputs(), args).enumerate() {
             let op_arg_ty = op_arg.ty(body, self.tcx());
+
             let op_arg_ty = self.normalize(op_arg_ty, term_location);
             let category = if from_hir_call {
-                ConstraintCategory::CallArgument
+                ConstraintCategory::CallArgument(func_ty)
             } else {
                 ConstraintCategory::Boring
             };
@@ -1658,8 +1694,8 @@
                     self.assert_iscleanup(body, block_data, unwind, true);
                 }
             }
-            TerminatorKind::Call { ref destination, cleanup, .. } => {
-                if let &Some((_, target)) = destination {
+            TerminatorKind::Call { ref target, cleanup, .. } => {
+                if let &Some(target) = target {
                     self.assert_iscleanup(body, block_data, target, is_cleanup);
                 }
                 if let Some(cleanup) = cleanup {
@@ -1809,7 +1845,7 @@
     fn check_operand(&mut self, op: &Operand<'tcx>, location: Location) {
         if let Operand::Constant(constant) = op {
             let maybe_uneval = match constant.literal {
-                ConstantKind::Ty(ct) => match ct.val() {
+                ConstantKind::Ty(ct) => match ct.kind() {
                     ty::ConstKind::Unevaluated(uv) => Some(uv),
                     _ => None,
                 },
@@ -1837,6 +1873,7 @@
         }
     }
 
+    #[instrument(skip(self, body), level = "debug")]
     fn check_rvalue(&mut self, body: &Body<'tcx>, rvalue: &Rvalue<'tcx>, location: Location) {
         let tcx = self.tcx();
 
@@ -2116,24 +2153,62 @@
                         }
                     }
 
-                    CastKind::Misc => {
+                    CastKind::PointerExposeAddress => {
                         let ty_from = op.ty(body, tcx);
                         let cast_ty_from = CastTy::from_ty(ty_from);
                         let cast_ty_to = CastTy::from_ty(*ty);
                         match (cast_ty_from, cast_ty_to) {
-                            (None, _)
-                            | (_, None | Some(CastTy::FnPtr))
-                            | (Some(CastTy::Float), Some(CastTy::Ptr(_)))
-                            | (Some(CastTy::Ptr(_) | CastTy::FnPtr), Some(CastTy::Float)) => {
-                                span_mirbug!(self, rvalue, "Invalid cast {:?} -> {:?}", ty_from, ty,)
+                            (Some(CastTy::Ptr(_) | CastTy::FnPtr), Some(CastTy::Int(_))) => (),
+                            _ => {
+                                span_mirbug!(
+                                    self,
+                                    rvalue,
+                                    "Invalid PointerExposeAddress cast {:?} -> {:?}",
+                                    ty_from,
+                                    ty
+                                )
                             }
+                        }
+                    }
+
+                    CastKind::PointerFromExposedAddress => {
+                        let ty_from = op.ty(body, tcx);
+                        let cast_ty_from = CastTy::from_ty(ty_from);
+                        let cast_ty_to = CastTy::from_ty(*ty);
+                        match (cast_ty_from, cast_ty_to) {
+                            (Some(CastTy::Int(_)), Some(CastTy::Ptr(_))) => (),
+                            _ => {
+                                span_mirbug!(
+                                    self,
+                                    rvalue,
+                                    "Invalid PointerFromExposedAddress cast {:?} -> {:?}",
+                                    ty_from,
+                                    ty
+                                )
+                            }
+                        }
+                    }
+
+                    CastKind::Misc => {
+                        let ty_from = op.ty(body, tcx);
+                        let cast_ty_from = CastTy::from_ty(ty_from);
+                        let cast_ty_to = CastTy::from_ty(*ty);
+                        // Misc casts are either between floats and ints, or one ptr type to another.
+                        match (cast_ty_from, cast_ty_to) {
                             (
-                                Some(CastTy::Int(_)),
-                                Some(CastTy::Int(_) | CastTy::Float | CastTy::Ptr(_)),
+                                Some(CastTy::Int(_) | CastTy::Float),
+                                Some(CastTy::Int(_) | CastTy::Float),
                             )
-                            | (Some(CastTy::Float), Some(CastTy::Int(_) | CastTy::Float))
-                            | (Some(CastTy::Ptr(_)), Some(CastTy::Int(_) | CastTy::Ptr(_)))
-                            | (Some(CastTy::FnPtr), Some(CastTy::Int(_) | CastTy::Ptr(_))) => (),
+                            | (Some(CastTy::Ptr(_) | CastTy::FnPtr), Some(CastTy::Ptr(_))) => (),
+                            _ => {
+                                span_mirbug!(
+                                    self,
+                                    rvalue,
+                                    "Invalid Misc cast {:?} -> {:?}",
+                                    ty_from,
+                                    ty,
+                                )
+                            }
                         }
                     }
                 }
diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs
index f98d2c3..c45850c 100644
--- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs
+++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs
@@ -28,7 +28,7 @@
         v: ty::Variance,
         b: Ty<'tcx>,
         locations: Locations,
-        category: ConstraintCategory,
+        category: ConstraintCategory<'tcx>,
     ) -> Fallible<()> {
         TypeRelating::new(
             self.infcx,
@@ -47,7 +47,7 @@
     locations: Locations,
 
     /// What category do we assign the resulting `'a: 'b` relationships?
-    category: ConstraintCategory,
+    category: ConstraintCategory<'tcx>,
 
     /// Information so that error reporting knows what types we are relating
     /// when reporting a bound region error.
@@ -58,7 +58,7 @@
     fn new(
         type_checker: &'me mut TypeChecker<'bccx, 'tcx>,
         locations: Locations,
-        category: ConstraintCategory,
+        category: ConstraintCategory<'tcx>,
         universe_info: UniverseInfo<'tcx>,
     ) -> Self {
         Self { type_checker, locations, category, universe_info }
diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs
index 0fcac9a..c2c093f 100644
--- a/compiler/rustc_borrowck/src/universal_regions.rs
+++ b/compiler/rustc_borrowck/src/universal_regions.rs
@@ -336,7 +336,7 @@
     /// that this region imposes on others. The methods in this file
     /// handle the part about dumping the inference context internal
     /// state.
-    crate fn annotate(&self, tcx: TyCtxt<'tcx>, err: &mut Diagnostic) {
+    pub(crate) fn annotate(&self, tcx: TyCtxt<'tcx>, err: &mut Diagnostic) {
         match self.defining_ty {
             DefiningTy::Closure(def_id, substs) => {
                 err.note(&format!(
@@ -830,11 +830,11 @@
     fn_def_id: DefId,
     mut f: impl FnMut(ty::Region<'tcx>),
 ) {
-    if let Some((owner, late_bounds)) = tcx.is_late_bound_map(fn_def_id.expect_local()) {
+    if let Some(late_bounds) = tcx.is_late_bound_map(fn_def_id.expect_local()) {
         for &region_def_id in late_bounds.iter() {
             let name = tcx.item_name(region_def_id.to_def_id());
             let liberated_region = tcx.mk_region(ty::ReFree(ty::FreeRegion {
-                scope: owner.to_def_id(),
+                scope: fn_def_id,
                 bound_region: ty::BoundRegionKind::BrNamed(region_def_id.to_def_id(), name),
             }));
             f(liberated_region);
diff --git a/compiler/rustc_borrowck/src/used_muts.rs b/compiler/rustc_borrowck/src/used_muts.rs
index 6022a98..1093167 100644
--- a/compiler/rustc_borrowck/src/used_muts.rs
+++ b/compiler/rustc_borrowck/src/used_muts.rs
@@ -22,7 +22,7 @@
     ///  been assigned to - this set is used as a proxy for locals that were not initialized due to
     ///  unreachable code. These locals are then considered "used" to silence the lint for them.
     ///  See #55344 for context.
-    crate fn gather_used_muts(
+    pub(crate) fn gather_used_muts(
         &mut self,
         temporary_used_locals: FxHashSet<Local>,
         mut never_initialized_mut_locals: FxHashSet<Local>,
@@ -66,8 +66,8 @@
     fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) {
         debug!("visit_terminator: terminator={:?}", terminator);
         match &terminator.kind {
-            TerminatorKind::Call { destination: Some((into, _)), .. } => {
-                self.remove_never_initialized_mut_locals(*into);
+            TerminatorKind::Call { destination, .. } => {
+                self.remove_never_initialized_mut_locals(*destination);
             }
             TerminatorKind::DropAndReplace { place, .. } => {
                 self.remove_never_initialized_mut_locals(*place);
diff --git a/compiler/rustc_builtin_macros/Cargo.toml b/compiler/rustc_builtin_macros/Cargo.toml
index 9031c3b..7dc947f 100644
--- a/compiler/rustc_builtin_macros/Cargo.toml
+++ b/compiler/rustc_builtin_macros/Cargo.toml
@@ -16,6 +16,7 @@
 rustc_feature = { path = "../rustc_feature" }
 rustc_lexer = { path = "../rustc_lexer" }
 rustc_lint_defs = { path = "../rustc_lint_defs" }
+rustc_macros = { path = "../rustc_macros" }
 rustc_parse = { path = "../rustc_parse" }
 rustc_target = { path = "../rustc_target" }
 rustc_session = { path = "../rustc_session" }
diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs
index c95d714..42bddd1 100644
--- a/compiler/rustc_builtin_macros/src/asm.rs
+++ b/compiler/rustc_builtin_macros/src/asm.rs
@@ -363,7 +363,7 @@
     err.tool_only_span_suggestion(
         full_span,
         "remove this option",
-        String::new(),
+        "",
         Applicability::MachineApplicable,
     );
 
diff --git a/compiler/rustc_builtin_macros/src/assert.rs b/compiler/rustc_builtin_macros/src/assert.rs
index a984980..925c36e 100644
--- a/compiler/rustc_builtin_macros/src/assert.rs
+++ b/compiler/rustc_builtin_macros/src/assert.rs
@@ -1,11 +1,13 @@
+mod context;
+
 use crate::edition_panic::use_panic_2021;
 use rustc_ast::ptr::P;
 use rustc_ast::token;
 use rustc_ast::tokenstream::{DelimSpan, TokenStream};
-use rustc_ast::{self as ast, *};
+use rustc_ast::{Expr, ExprKind, MacArgs, MacCall, MacDelimiter, Path, PathSegment, UnOp};
 use rustc_ast_pretty::pprust;
 use rustc_errors::{Applicability, PResult};
-use rustc_expand::base::*;
+use rustc_expand::base::{DummyResult, ExtCtxt, MacEager, MacResult};
 use rustc_parse::parser::Parser;
 use rustc_span::symbol::{sym, Ident, Symbol};
 use rustc_span::{Span, DUMMY_SP};
@@ -25,13 +27,13 @@
 
     // `core::panic` and `std::panic` are different macros, so we use call-site
     // context to pick up whichever is currently in scope.
-    let sp = cx.with_call_site_ctxt(span);
+    let call_site_span = cx.with_call_site_ctxt(span);
 
-    let panic_call = if let Some(tokens) = custom_message {
-        let path = if use_panic_2021(span) {
+    let panic_path = || {
+        if use_panic_2021(span) {
             // On edition 2021, we always call `$crate::panic::panic_2021!()`.
             Path {
-                span: sp,
+                span: call_site_span,
                 segments: cx
                     .std_path(&[sym::panic, sym::panic_2021])
                     .into_iter()
@@ -42,27 +44,40 @@
         } else {
             // Before edition 2021, we call `panic!()` unqualified,
             // such that it calls either `std::panic!()` or `core::panic!()`.
-            Path::from_ident(Ident::new(sym::panic, sp))
-        };
-        // Pass the custom message to panic!().
-        cx.expr(
-            sp,
+            Path::from_ident(Ident::new(sym::panic, call_site_span))
+        }
+    };
+
+    // Simply uses the user provided message instead of generating custom outputs
+    let expr = if let Some(tokens) = custom_message {
+        let then = cx.expr(
+            call_site_span,
             ExprKind::MacCall(MacCall {
-                path,
+                path: panic_path(),
                 args: P(MacArgs::Delimited(
-                    DelimSpan::from_single(sp),
+                    DelimSpan::from_single(call_site_span),
                     MacDelimiter::Parenthesis,
                     tokens,
                 )),
                 prior_type_ascription: None,
             }),
-        )
-    } else {
+        );
+        expr_if_not(cx, call_site_span, cond_expr, then, None)
+    }
+    // If `generic_assert` is enabled, generates rich captured outputs
+    //
+    // FIXME(c410-f3r) See https://github.com/rust-lang/rust/issues/96949
+    else if let Some(features) = cx.ecfg.features && features.generic_assert {
+        context::Context::new(cx, call_site_span).build(cond_expr, panic_path())
+    }
+    // If `generic_assert` is not enabled, only outputs a literal "assertion failed: ..."
+    // string
+    else {
         // Pass our own message directly to $crate::panicking::panic(),
         // because it might contain `{` and `}` that should always be
         // passed literally.
-        cx.expr_call_global(
-            sp,
+        let then = cx.expr_call_global(
+            call_site_span,
             cx.std_path(&[sym::panicking, sym::panic]),
             vec![cx.expr_str(
                 DUMMY_SP,
@@ -71,18 +86,29 @@
                     pprust::expr_to_string(&cond_expr).escape_debug()
                 )),
             )],
-        )
+        );
+        expr_if_not(cx, call_site_span, cond_expr, then, None)
     };
-    let if_expr =
-        cx.expr_if(sp, cx.expr(sp, ExprKind::Unary(UnOp::Not, cond_expr)), panic_call, None);
-    MacEager::expr(if_expr)
+
+    MacEager::expr(expr)
 }
 
 struct Assert {
-    cond_expr: P<ast::Expr>,
+    cond_expr: P<Expr>,
     custom_message: Option<TokenStream>,
 }
 
+// if !{ ... } { ... } else { ... }
+fn expr_if_not(
+    cx: &ExtCtxt<'_>,
+    span: Span,
+    cond: P<Expr>,
+    then: P<Expr>,
+    els: Option<P<Expr>>,
+) -> P<Expr> {
+    cx.expr_if(span, cx.expr(span, ExprKind::Unary(UnOp::Not, cond)), then, els)
+}
+
 fn parse_assert<'a>(cx: &mut ExtCtxt<'a>, sp: Span, stream: TokenStream) -> PResult<'a, Assert> {
     let mut parser = cx.new_parser_from_tts(stream);
 
@@ -106,7 +132,7 @@
         err.span_suggestion(
             parser.token.span,
             "try removing semicolon",
-            String::new(),
+            "",
             Applicability::MaybeIncorrect,
         );
         err.emit();
@@ -127,7 +153,7 @@
             err.span_suggestion_short(
                 comma_span,
                 "try adding a comma",
-                ", ".to_string(),
+                ", ",
                 Applicability::MaybeIncorrect,
             );
             err.emit();
diff --git a/compiler/rustc_builtin_macros/src/assert/context.rs b/compiler/rustc_builtin_macros/src/assert/context.rs
new file mode 100644
index 0000000..cad3018
--- /dev/null
+++ b/compiler/rustc_builtin_macros/src/assert/context.rs
@@ -0,0 +1,387 @@
+use crate::assert::expr_if_not;
+use rustc_ast::{
+    attr,
+    ptr::P,
+    token,
+    tokenstream::{DelimSpan, TokenStream, TokenTree},
+    BorrowKind, Expr, ExprKind, ItemKind, MacArgs, MacCall, MacDelimiter, Mutability, Path,
+    PathSegment, Stmt, StructRest, UseTree, UseTreeKind, DUMMY_NODE_ID,
+};
+use rustc_ast_pretty::pprust;
+use rustc_data_structures::fx::FxHashSet;
+use rustc_expand::base::ExtCtxt;
+use rustc_span::{
+    symbol::{sym, Ident, Symbol},
+    Span,
+};
+
+pub(super) struct Context<'cx, 'a> {
+    // Top-level `let captureN = Capture::new()` statements
+    capture_decls: Vec<Capture>,
+    cx: &'cx ExtCtxt<'a>,
+    // Formatting string used for debugging
+    fmt_string: String,
+    // Top-level `let __local_bindN = &expr` statements
+    local_bind_decls: Vec<Stmt>,
+    // Used to avoid capturing duplicated paths
+    //
+    // ```rust
+    // let a = 1i32;
+    // assert!(add(a, a) == 3);
+    // ```
+    paths: FxHashSet<Ident>,
+    span: Span,
+}
+
+impl<'cx, 'a> Context<'cx, 'a> {
+    pub(super) fn new(cx: &'cx ExtCtxt<'a>, span: Span) -> Self {
+        Self {
+            capture_decls: <_>::default(),
+            cx,
+            fmt_string: <_>::default(),
+            local_bind_decls: <_>::default(),
+            paths: <_>::default(),
+            span,
+        }
+    }
+
+    /// Builds the whole `assert!` expression. For example, `let elem = 1; assert!(elem == 1);` expands to:
+    ///
+    /// ```rust
+    /// let elem = 1;
+    /// {
+    ///   #[allow(unused_imports)]
+    ///   use ::core::asserting::{TryCaptureGeneric, TryCapturePrintable};
+    ///   let mut __capture0 = ::core::asserting::Capture::new();
+    ///   let __local_bind0 = &elem;
+    ///   if !(
+    ///     *{
+    ///       (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0);
+    ///       __local_bind0
+    ///     } == 1
+    ///   ) {
+    ///     panic!("Assertion failed: elem == 1\nWith captures:\n  elem = {}", __capture0)
+    ///   }
+    /// }
+    /// ```
+    pub(super) fn build(mut self, mut cond_expr: P<Expr>, panic_path: Path) -> P<Expr> {
+        let expr_str = pprust::expr_to_string(&cond_expr);
+        self.manage_cond_expr(&mut cond_expr);
+        let initial_imports = self.build_initial_imports();
+        let panic = self.build_panic(&expr_str, panic_path);
+
+        let Self { capture_decls, cx, local_bind_decls, span, .. } = self;
+
+        let mut stmts = Vec::with_capacity(4);
+        stmts.push(initial_imports);
+        stmts.extend(capture_decls.into_iter().map(|c| c.decl));
+        stmts.extend(local_bind_decls);
+        stmts.push(cx.stmt_expr(expr_if_not(cx, span, cond_expr, panic, None)));
+        cx.expr_block(cx.block(span, stmts))
+    }
+
+    /// Initial **trait** imports
+    ///
+    /// use ::core::asserting::{ ... };
+    fn build_initial_imports(&self) -> Stmt {
+        let nested_tree = |this: &Self, sym| {
+            (
+                UseTree {
+                    prefix: this.cx.path(this.span, vec![Ident::with_dummy_span(sym)]),
+                    kind: UseTreeKind::Simple(None, DUMMY_NODE_ID, DUMMY_NODE_ID),
+                    span: this.span,
+                },
+                DUMMY_NODE_ID,
+            )
+        };
+        self.cx.stmt_item(
+            self.span,
+            self.cx.item(
+                self.span,
+                Ident::empty(),
+                vec![self.cx.attribute(attr::mk_list_item(
+                    Ident::new(sym::allow, self.span),
+                    vec![attr::mk_nested_word_item(Ident::new(sym::unused_imports, self.span))],
+                ))],
+                ItemKind::Use(UseTree {
+                    prefix: self.cx.path(self.span, self.cx.std_path(&[sym::asserting])),
+                    kind: UseTreeKind::Nested(vec![
+                        nested_tree(self, sym::TryCaptureGeneric),
+                        nested_tree(self, sym::TryCapturePrintable),
+                    ]),
+                    span: self.span,
+                }),
+            ),
+        )
+    }
+
+    /// The necessary custom `panic!(...)` expression.
+    ///
+    /// panic!(
+    ///     "Assertion failed: ... \n With expansion: ...",
+    ///     __capture0,
+    ///     ...
+    /// );
+    fn build_panic(&self, expr_str: &str, panic_path: Path) -> P<Expr> {
+        let escaped_expr_str = escape_to_fmt(expr_str);
+        let initial = [
+            TokenTree::token(
+                token::Literal(token::Lit {
+                    kind: token::LitKind::Str,
+                    symbol: Symbol::intern(&if self.fmt_string.is_empty() {
+                        format!("Assertion failed: {escaped_expr_str}")
+                    } else {
+                        format!(
+                            "Assertion failed: {escaped_expr_str}\nWith captures:\n{}",
+                            &self.fmt_string
+                        )
+                    }),
+                    suffix: None,
+                }),
+                self.span,
+            ),
+            TokenTree::token(token::Comma, self.span),
+        ];
+        let captures = self.capture_decls.iter().flat_map(|cap| {
+            [
+                TokenTree::token(token::Ident(cap.ident.name, false), cap.ident.span),
+                TokenTree::token(token::Comma, self.span),
+            ]
+        });
+        self.cx.expr(
+            self.span,
+            ExprKind::MacCall(MacCall {
+                path: panic_path,
+                args: P(MacArgs::Delimited(
+                    DelimSpan::from_single(self.span),
+                    MacDelimiter::Parenthesis,
+                    initial.into_iter().chain(captures).collect::<TokenStream>(),
+                )),
+                prior_type_ascription: None,
+            }),
+        )
+    }
+
+    /// Recursive function called until `cond_expr` and `fmt_str` are fully modified.
+    ///
+    /// See [Self::manage_initial_capture] and [Self::manage_try_capture]
+    fn manage_cond_expr(&mut self, expr: &mut P<Expr>) {
+        match (*expr).kind {
+            ExprKind::AddrOf(_, _, ref mut local_expr) => {
+                self.manage_cond_expr(local_expr);
+            }
+            ExprKind::Array(ref mut local_exprs) => {
+                for local_expr in local_exprs {
+                    self.manage_cond_expr(local_expr);
+                }
+            }
+            ExprKind::Binary(_, ref mut lhs, ref mut rhs) => {
+                self.manage_cond_expr(lhs);
+                self.manage_cond_expr(rhs);
+            }
+            ExprKind::Call(_, ref mut local_exprs) => {
+                for local_expr in local_exprs {
+                    self.manage_cond_expr(local_expr);
+                }
+            }
+            ExprKind::Cast(ref mut local_expr, _) => {
+                self.manage_cond_expr(local_expr);
+            }
+            ExprKind::Index(ref mut prefix, ref mut suffix) => {
+                self.manage_cond_expr(prefix);
+                self.manage_cond_expr(suffix);
+            }
+            ExprKind::MethodCall(_, ref mut local_exprs, _) => {
+                for local_expr in local_exprs.iter_mut().skip(1) {
+                    self.manage_cond_expr(local_expr);
+                }
+            }
+            ExprKind::Path(_, Path { ref segments, .. }) if let &[ref path_segment] = &segments[..] => {
+                let path_ident = path_segment.ident;
+                self.manage_initial_capture(expr, path_ident);
+            }
+            ExprKind::Paren(ref mut local_expr) => {
+                self.manage_cond_expr(local_expr);
+            }
+            ExprKind::Range(ref mut prefix, ref mut suffix, _) => {
+                if let Some(ref mut elem) = prefix {
+                    self.manage_cond_expr(elem);
+                }
+                if let Some(ref mut elem) = suffix {
+                    self.manage_cond_expr(elem);
+                }
+            }
+            ExprKind::Repeat(ref mut local_expr, ref mut elem) => {
+                self.manage_cond_expr(local_expr);
+                self.manage_cond_expr(&mut elem.value);
+            }
+            ExprKind::Struct(ref mut elem) => {
+                for field in &mut elem.fields {
+                    self.manage_cond_expr(&mut field.expr);
+                }
+                if let StructRest::Base(ref mut local_expr) = elem.rest {
+                    self.manage_cond_expr(local_expr);
+                }
+            }
+            ExprKind::Tup(ref mut local_exprs) => {
+                for local_expr in local_exprs {
+                    self.manage_cond_expr(local_expr);
+                }
+            }
+            ExprKind::Unary(_, ref mut local_expr) => {
+                self.manage_cond_expr(local_expr);
+            }
+            // Expressions that are not worth or can not be captured.
+            //
+            // Full list instead of `_` to catch possible future inclusions and to
+            // sync with the `rfc-2011-nicer-assert-messages/all-expr-kinds.rs` test.
+            ExprKind::Assign(_, _, _)
+            | ExprKind::AssignOp(_, _, _)
+            | ExprKind::Async(_, _, _)
+            | ExprKind::Await(_)
+            | ExprKind::Block(_, _)
+            | ExprKind::Box(_)
+            | ExprKind::Break(_, _)
+            | ExprKind::Closure(_, _, _, _, _, _)
+            | ExprKind::ConstBlock(_)
+            | ExprKind::Continue(_)
+            | ExprKind::Err
+            | ExprKind::Field(_, _)
+            | ExprKind::ForLoop(_, _, _, _)
+            | ExprKind::If(_, _, _)
+            | ExprKind::InlineAsm(_)
+            | ExprKind::Let(_, _, _)
+            | ExprKind::Lit(_)
+            | ExprKind::Loop(_, _)
+            | ExprKind::MacCall(_)
+            | ExprKind::Match(_, _)
+            | ExprKind::Path(_, _)
+            | ExprKind::Ret(_)
+            | ExprKind::Try(_)
+            | ExprKind::TryBlock(_)
+            | ExprKind::Type(_, _)
+            | ExprKind::Underscore
+            | ExprKind::While(_, _, _)
+            | ExprKind::Yeet(_)
+            | ExprKind::Yield(_) => {}
+        }
+    }
+
+    /// Pushes the top-level declarations and modifies `expr` to try capturing variables.
+    ///
+    /// `fmt_str`, the formatting string used for debugging, is constructed to show possible
+    /// captured variables.
+    fn manage_initial_capture(&mut self, expr: &mut P<Expr>, path_ident: Ident) {
+        if self.paths.contains(&path_ident) {
+            return;
+        } else {
+            self.fmt_string.push_str("  ");
+            self.fmt_string.push_str(path_ident.as_str());
+            self.fmt_string.push_str(" = {:?}\n");
+            let _ = self.paths.insert(path_ident);
+        }
+        let curr_capture_idx = self.capture_decls.len();
+        let capture_string = format!("__capture{curr_capture_idx}");
+        let ident = Ident::new(Symbol::intern(&capture_string), self.span);
+        let init_std_path = self.cx.std_path(&[sym::asserting, sym::Capture, sym::new]);
+        let init = self.cx.expr_call(
+            self.span,
+            self.cx.expr_path(self.cx.path(self.span, init_std_path)),
+            vec![],
+        );
+        let capture = Capture { decl: self.cx.stmt_let(self.span, true, ident, init), ident };
+        self.capture_decls.push(capture);
+        self.manage_try_capture(ident, curr_capture_idx, expr);
+    }
+
+    /// Tries to copy `__local_bindN` into `__captureN`.
+    ///
+    /// *{
+    ///    (&Wrapper(__local_bindN)).try_capture(&mut __captureN);
+    ///    __local_bindN
+    /// }
+    fn manage_try_capture(&mut self, capture: Ident, curr_capture_idx: usize, expr: &mut P<Expr>) {
+        let local_bind_string = format!("__local_bind{curr_capture_idx}");
+        let local_bind = Ident::new(Symbol::intern(&local_bind_string), self.span);
+        self.local_bind_decls.push(self.cx.stmt_let(
+            self.span,
+            false,
+            local_bind,
+            self.cx.expr_addr_of(self.span, expr.clone()),
+        ));
+        let wrapper = self.cx.expr_call(
+            self.span,
+            self.cx.expr_path(
+                self.cx.path(self.span, self.cx.std_path(&[sym::asserting, sym::Wrapper])),
+            ),
+            vec![self.cx.expr_path(Path::from_ident(local_bind))],
+        );
+        let try_capture_call = self
+            .cx
+            .stmt_expr(expr_method_call(
+                self.cx,
+                PathSegment {
+                    args: None,
+                    id: DUMMY_NODE_ID,
+                    ident: Ident::new(sym::try_capture, self.span),
+                },
+                vec![
+                    expr_paren(self.cx, self.span, self.cx.expr_addr_of(self.span, wrapper)),
+                    expr_addr_of_mut(
+                        self.cx,
+                        self.span,
+                        self.cx.expr_path(Path::from_ident(capture)),
+                    ),
+                ],
+                self.span,
+            ))
+            .add_trailing_semicolon();
+        let local_bind_path = self.cx.expr_path(Path::from_ident(local_bind));
+        let ret = self.cx.stmt_expr(local_bind_path);
+        let block = self.cx.expr_block(self.cx.block(self.span, vec![try_capture_call, ret]));
+        *expr = self.cx.expr_deref(self.span, block);
+    }
+}
+
+/// Information about a captured element.
+#[derive(Debug)]
+struct Capture {
+    // Generated indexed `Capture` statement.
+    //
+    // `let __capture{} = Capture::new();`
+    decl: Stmt,
+    // The name of the generated indexed `Capture` variable.
+    //
+    // `__capture{}`
+    ident: Ident,
+}
+
+/// Escapes to use as a formatting string.
+fn escape_to_fmt(s: &str) -> String {
+    let mut rslt = String::with_capacity(s.len());
+    for c in s.chars() {
+        rslt.extend(c.escape_debug());
+        match c {
+            '{' | '}' => rslt.push(c),
+            _ => {}
+        }
+    }
+    rslt
+}
+
+fn expr_addr_of_mut(cx: &ExtCtxt<'_>, sp: Span, e: P<Expr>) -> P<Expr> {
+    cx.expr(sp, ExprKind::AddrOf(BorrowKind::Ref, Mutability::Mut, e))
+}
+
+fn expr_method_call(
+    cx: &ExtCtxt<'_>,
+    path: PathSegment,
+    args: Vec<P<Expr>>,
+    span: Span,
+) -> P<Expr> {
+    cx.expr(span, ExprKind::MethodCall(path, args, span))
+}
+
+fn expr_paren(cx: &ExtCtxt<'_>, sp: Span, e: P<Expr>) -> P<Expr> {
+    cx.expr(sp, ExprKind::Paren(e))
+}
diff --git a/compiler/rustc_builtin_macros/src/cfg.rs b/compiler/rustc_builtin_macros/src/cfg.rs
index f5ef476..c75d83b 100644
--- a/compiler/rustc_builtin_macros/src/cfg.rs
+++ b/compiler/rustc_builtin_macros/src/cfg.rs
@@ -8,6 +8,7 @@
 use rustc_attr as attr;
 use rustc_errors::PResult;
 use rustc_expand::base::{self, *};
+use rustc_macros::SessionDiagnostic;
 use rustc_span::Span;
 
 pub fn expand_cfg(
@@ -34,13 +35,26 @@
     }
 }
 
-fn parse_cfg<'a>(cx: &mut ExtCtxt<'a>, sp: Span, tts: TokenStream) -> PResult<'a, ast::MetaItem> {
+#[derive(SessionDiagnostic)]
+#[error(slug = "builtin-macros-requires-cfg-pattern")]
+struct RequiresCfgPattern {
+    #[primary_span]
+    #[label]
+    span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(slug = "builtin-macros-expected-one-cfg-pattern")]
+struct OneCfgPattern {
+    #[primary_span]
+    span: Span,
+}
+
+fn parse_cfg<'a>(cx: &mut ExtCtxt<'a>, span: Span, tts: TokenStream) -> PResult<'a, ast::MetaItem> {
     let mut p = cx.new_parser_from_tts(tts);
 
     if p.token == token::Eof {
-        let mut err = cx.struct_span_err(sp, "macro requires a cfg-pattern as an argument");
-        err.span_label(sp, "cfg-pattern required");
-        return Err(err);
+        return Err(cx.create_err(RequiresCfgPattern { span }));
     }
 
     let cfg = p.parse_meta_item()?;
@@ -48,7 +62,7 @@
     let _ = p.eat(&token::Comma);
 
     if !p.eat(&token::Eof) {
-        return Err(cx.struct_span_err(sp, "expected 1 cfg-pattern"));
+        return Err(cx.create_err(OneCfgPattern { span }));
     }
 
     Ok(cfg)
diff --git a/compiler/rustc_builtin_macros/src/cfg_accessible.rs b/compiler/rustc_builtin_macros/src/cfg_accessible.rs
index 7b7db3e..cb5359d 100644
--- a/compiler/rustc_builtin_macros/src/cfg_accessible.rs
+++ b/compiler/rustc_builtin_macros/src/cfg_accessible.rs
@@ -7,7 +7,7 @@
 use rustc_span::symbol::sym;
 use rustc_span::Span;
 
-crate struct Expander;
+pub(crate) struct Expander;
 
 fn validate_input<'a>(ecx: &mut ExtCtxt<'_>, mi: &'a ast::MetaItem) -> Option<&'a ast::Path> {
     match mi.meta_item_list() {
diff --git a/compiler/rustc_builtin_macros/src/cfg_eval.rs b/compiler/rustc_builtin_macros/src/cfg_eval.rs
index 4278fed..89b2c32 100644
--- a/compiler/rustc_builtin_macros/src/cfg_eval.rs
+++ b/compiler/rustc_builtin_macros/src/cfg_eval.rs
@@ -3,7 +3,6 @@
 use rustc_ast as ast;
 use rustc_ast::mut_visit::MutVisitor;
 use rustc_ast::ptr::P;
-use rustc_ast::tokenstream::CanSynthesizeMissingTokens;
 use rustc_ast::visit::Visitor;
 use rustc_ast::NodeId;
 use rustc_ast::{mut_visit, visit};
@@ -13,13 +12,12 @@
 use rustc_expand::configure;
 use rustc_feature::Features;
 use rustc_parse::parser::{ForceCollect, Parser};
-use rustc_session::utils::FlattenNonterminals;
 use rustc_session::Session;
 use rustc_span::symbol::sym;
 use rustc_span::Span;
 use smallvec::SmallVec;
 
-crate fn expand(
+pub(crate) fn expand(
     ecx: &mut ExtCtxt<'_>,
     _span: Span,
     meta_item: &ast::MetaItem,
@@ -30,7 +28,7 @@
     vec![cfg_eval(ecx.sess, ecx.ecfg.features, annotatable, ecx.current_expansion.lint_node_id)]
 }
 
-crate fn cfg_eval(
+pub(crate) fn cfg_eval(
     sess: &Session,
     features: Option<&Features>,
     annotatable: Annotatable,
@@ -174,8 +172,6 @@
             _ => unreachable!(),
         };
 
-        let mut orig_tokens = annotatable.to_tokens(&self.cfg.sess.parse_sess);
-
         // 'Flatten' all nonterminals (i.e. `TokenKind::Interpolated`)
         // to `None`-delimited groups containing the corresponding tokens. This
         // is normally delayed until the proc-macro server actually needs to
@@ -189,12 +185,7 @@
         // where `$item` is `#[cfg_attr] struct Foo {}`. We want to make
         // sure to evaluate *all* `#[cfg]` and `#[cfg_attr]` attributes - the simplest
         // way to do this is to do a single parse of a stream without any nonterminals.
-        let mut flatten = FlattenNonterminals {
-            nt_to_tokenstream: rustc_parse::nt_to_tokenstream,
-            parse_sess: &self.cfg.sess.parse_sess,
-            synthesize_tokens: CanSynthesizeMissingTokens::No,
-        };
-        orig_tokens = flatten.process_token_stream(orig_tokens);
+        let orig_tokens = annotatable.to_tokens().flattened();
 
         // Re-parse the tokens, setting the `capture_cfg` flag to save extra information
         // to the captured `AttrAnnotatedTokenStream` (specifically, we capture
diff --git a/compiler/rustc_builtin_macros/src/derive.rs b/compiler/rustc_builtin_macros/src/derive.rs
index 391c46d..d3de10c 100644
--- a/compiler/rustc_builtin_macros/src/derive.rs
+++ b/compiler/rustc_builtin_macros/src/derive.rs
@@ -10,7 +10,7 @@
 use rustc_span::symbol::{sym, Ident};
 use rustc_span::Span;
 
-crate struct Expander;
+pub(crate) struct Expander;
 
 impl MultiItemModifier for Expander {
     fn expand(
@@ -142,7 +142,7 @@
     let report_error = |title, action| {
         let span = meta.span.with_lo(meta.path.span.hi());
         sess.struct_span_err(span, title)
-            .span_suggestion(span, action, String::new(), Applicability::MachineApplicable)
+            .span_suggestion(span, action, "", Applicability::MachineApplicable)
             .emit();
     };
     match meta.kind {
diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
index 0fd23fd..53369af 100644
--- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
@@ -257,7 +257,7 @@
     pub type_ident: Ident,
     /// ident of the method
     pub method_ident: Ident,
-    /// dereferenced access to any [`Self_`] or [`Ptr(Self_, _)][ptr]` arguments
+    /// dereferenced access to any [`Self_`] or [`Ptr(Self_, _)`][ptr] arguments
     ///
     /// [`Self_`]: ty::Ty::Self_
     /// [ptr]: ty::Ty::Ptr
@@ -1039,7 +1039,9 @@
         let span = trait_.span;
         let mut patterns = Vec::new();
         for i in 0..self_args.len() {
-            let struct_path = cx.path(span, vec![type_ident]);
+            // We could use `type_ident` instead of `Self`, but in the case of a type parameter
+            // shadowing the struct name, that causes a second, unnecessary E0578 error. #97343
+            let struct_path = cx.path(span, vec![Ident::new(kw::SelfUpper, type_ident.span)]);
             let (pat, ident_expr) = trait_.create_struct_pattern(
                 cx,
                 struct_path,
diff --git a/compiler/rustc_builtin_macros/src/deriving/mod.rs b/compiler/rustc_builtin_macros/src/deriving/mod.rs
index 812d86a..c678c8c 100644
--- a/compiler/rustc_builtin_macros/src/deriving/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/mod.rs
@@ -38,8 +38,8 @@
 
 pub mod generic;
 
-crate struct BuiltinDerive(
-    crate fn(&mut ExtCtxt<'_>, Span, &MetaItem, &Annotatable, &mut dyn FnMut(Annotatable)),
+pub(crate) struct BuiltinDerive(
+    pub(crate) fn(&mut ExtCtxt<'_>, Span, &MetaItem, &Annotatable, &mut dyn FnMut(Annotatable)),
 );
 
 impl MultiItemModifier for BuiltinDerive {
diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs
index 60b9639..10348c4 100644
--- a/compiler/rustc_builtin_macros/src/format.rs
+++ b/compiler/rustc_builtin_macros/src/format.rs
@@ -330,7 +330,7 @@
                                 err.tool_only_span_suggestion(
                                     sp,
                                     &format!("use the `{}` trait", name),
-                                    (*fmt).to_string(),
+                                    *fmt,
                                     Applicability::MaybeIncorrect,
                                 );
                             }
diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs
index 468ca7d..11565ba 100644
--- a/compiler/rustc_builtin_macros/src/lib.rs
+++ b/compiler/rustc_builtin_macros/src/lib.rs
@@ -1,18 +1,18 @@
 //! This crate contains implementations of built-in macros and other code generating facilities
 //! injecting code into the crate before it is lowered to HIR.
 
+#![allow(rustc::potential_query_instability)]
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![feature(array_windows)]
 #![feature(box_patterns)]
-#![feature(crate_visibility_modifier)]
 #![feature(decl_macro)]
+#![feature(if_let_guard)]
 #![feature(is_sorted)]
-#![feature(nll)]
+#![feature(let_chains)]
 #![feature(let_else)]
 #![feature(proc_macro_internals)]
 #![feature(proc_macro_quote)]
 #![recursion_limit = "256"]
-#![allow(rustc::potential_query_instability)]
 
 extern crate proc_macro;
 
diff --git a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs
index 407ca23..03159d43 100644
--- a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs
+++ b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs
@@ -22,21 +22,16 @@
     attrs: Vec<Symbol>,
 }
 
-enum ProcMacroDefType {
-    Attr,
-    Bang,
-}
-
 struct ProcMacroDef {
     id: NodeId,
     function_name: Ident,
     span: Span,
-    def_type: ProcMacroDefType,
 }
 
 enum ProcMacro {
     Derive(ProcMacroDerive),
-    Def(ProcMacroDef),
+    Attr(ProcMacroDef),
+    Bang(ProcMacroDef),
 }
 
 struct CollectProcMacros<'a> {
@@ -128,11 +123,10 @@
 
     fn collect_attr_proc_macro(&mut self, item: &'a ast::Item) {
         if self.in_root && item.vis.kind.is_pub() {
-            self.macros.push(ProcMacro::Def(ProcMacroDef {
+            self.macros.push(ProcMacro::Attr(ProcMacroDef {
                 id: item.id,
                 span: item.span,
                 function_name: item.ident,
-                def_type: ProcMacroDefType::Attr,
             }));
         } else {
             let msg = if !self.in_root {
@@ -147,11 +141,10 @@
 
     fn collect_bang_proc_macro(&mut self, item: &'a ast::Item) {
         if self.in_root && item.vis.kind.is_pub() {
-            self.macros.push(ProcMacro::Def(ProcMacroDef {
+            self.macros.push(ProcMacro::Bang(ProcMacroDef {
                 id: item.id,
                 span: item.span,
                 function_name: item.ident,
-                def_type: ProcMacroDefType::Bang,
             }));
         } else {
             let msg = if !self.in_root {
@@ -301,53 +294,57 @@
     // that we generate expressions. The position of each NodeId
     // in the 'proc_macros' Vec corresponds to its position
     // in the static array that will be generated
-    let decls = {
-        let local_path = |cx: &ExtCtxt<'_>, sp: Span, name| {
-            cx.expr_path(cx.path(sp.with_ctxt(span.ctxt()), vec![name]))
-        };
-        let proc_macro_ty_method_path = |cx: &ExtCtxt<'_>, method| {
-            cx.expr_path(cx.path(span, vec![proc_macro, bridge, client, proc_macro_ty, method]))
-        };
-        macros
-            .iter()
-            .map(|m| match m {
+    let decls = macros
+        .iter()
+        .map(|m| {
+            let harness_span = span;
+            let span = match m {
+                ProcMacro::Derive(m) => m.span,
+                ProcMacro::Attr(m) | ProcMacro::Bang(m) => m.span,
+            };
+            let local_path = |cx: &ExtCtxt<'_>, name| cx.expr_path(cx.path(span, vec![name]));
+            let proc_macro_ty_method_path = |cx: &ExtCtxt<'_>, method| {
+                cx.expr_path(cx.path(
+                    span.with_ctxt(harness_span.ctxt()),
+                    vec![proc_macro, bridge, client, proc_macro_ty, method],
+                ))
+            };
+            match m {
                 ProcMacro::Derive(cd) => {
                     cx.resolver.declare_proc_macro(cd.id);
                     cx.expr_call(
                         span,
                         proc_macro_ty_method_path(cx, custom_derive),
                         vec![
-                            cx.expr_str(cd.span, cd.trait_name),
+                            cx.expr_str(span, cd.trait_name),
                             cx.expr_vec_slice(
                                 span,
-                                cd.attrs
-                                    .iter()
-                                    .map(|&s| cx.expr_str(cd.span, s))
-                                    .collect::<Vec<_>>(),
+                                cd.attrs.iter().map(|&s| cx.expr_str(span, s)).collect::<Vec<_>>(),
                             ),
-                            local_path(cx, cd.span, cd.function_name),
+                            local_path(cx, cd.function_name),
                         ],
                     )
                 }
-                ProcMacro::Def(ca) => {
+                ProcMacro::Attr(ca) | ProcMacro::Bang(ca) => {
                     cx.resolver.declare_proc_macro(ca.id);
-                    let ident = match ca.def_type {
-                        ProcMacroDefType::Attr => attr,
-                        ProcMacroDefType::Bang => bang,
+                    let ident = match m {
+                        ProcMacro::Attr(_) => attr,
+                        ProcMacro::Bang(_) => bang,
+                        ProcMacro::Derive(_) => unreachable!(),
                     };
 
                     cx.expr_call(
                         span,
                         proc_macro_ty_method_path(cx, ident),
                         vec![
-                            cx.expr_str(ca.span, ca.function_name.name),
-                            local_path(cx, ca.span, ca.function_name),
+                            cx.expr_str(span, ca.function_name.name),
+                            local_path(cx, ca.function_name),
                         ],
                     )
                 }
-            })
-            .collect()
-    };
+            }
+        })
+        .collect();
 
     let decls_static = cx
         .item_static(
diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs
index 0c2d20b..e203756 100644
--- a/compiler/rustc_builtin_macros/src/test.rs
+++ b/compiler/rustc_builtin_macros/src/test.rs
@@ -118,7 +118,7 @@
         };
         err.span_label(attr_sp, "the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions")
             .span_label(item.span, format!("expected a non-associated function, found {} {}", item.kind.article(), item.kind.descr()))
-            .span_suggestion(attr_sp, "replace with conditional compilation to make the item only exist when tests are being run", String::from("#[cfg(test)]"), Applicability::MaybeIncorrect)
+            .span_suggestion(attr_sp, "replace with conditional compilation to make the item only exist when tests are being run", "#[cfg(test)]", Applicability::MaybeIncorrect)
             .emit();
 
         return vec![Annotatable::Item(item)];
diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs
index db8dce8..a08495f 100644
--- a/compiler/rustc_builtin_macros/src/test_harness.rs
+++ b/compiler/rustc_builtin_macros/src/test_harness.rs
@@ -147,7 +147,7 @@
             if sess.contains_name(&item.attrs, sym::start) {
                 EntryPointType::Start
             } else if sess.contains_name(&item.attrs, sym::rustc_main) {
-                EntryPointType::MainAttr
+                EntryPointType::RustcMainAttr
             } else if item.ident.name == sym::main {
                 if depth == 0 {
                     // This is a top-level function so can be 'main'
@@ -177,12 +177,12 @@
         let item = noop_flat_map_item(i, self).expect_one("noop did something");
         self.depth -= 1;
 
-        // Remove any #[main] or #[start] from the AST so it doesn't
+        // Remove any #[rustc_main] or #[start] from the AST so it doesn't
         // clash with the one we're going to add, but mark it as
         // #[allow(dead_code)] to avoid printing warnings.
         let item = match entry_point_type(self.sess, &item, self.depth) {
-            EntryPointType::MainNamed | EntryPointType::MainAttr | EntryPointType::Start => item
-                .map(|ast::Item { id, ident, attrs, kind, vis, span, tokens }| {
+            EntryPointType::MainNamed | EntryPointType::RustcMainAttr | EntryPointType::Start => {
+                item.map(|ast::Item { id, ident, attrs, kind, vis, span, tokens }| {
                     let allow_ident = Ident::new(sym::allow, self.def_site);
                     let dc_nested =
                         attr::mk_nested_word_item(Ident::new(sym::dead_code, self.def_site));
@@ -197,7 +197,8 @@
                         .collect();
 
                     ast::Item { id, ident, attrs, kind, vis, span, tokens }
-                }),
+                })
+            }
             EntryPointType::None | EntryPointType::OtherMain => item,
         };
 
diff --git a/compiler/rustc_codegen_cranelift/.github/workflows/main.yml b/compiler/rustc_codegen_cranelift/.github/workflows/main.yml
index 3aba528..aa556a2 100644
--- a/compiler/rustc_codegen_cranelift/.github/workflows/main.yml
+++ b/compiler/rustc_codegen_cranelift/.github/workflows/main.yml
@@ -10,7 +10,7 @@
     timeout-minutes: 10
 
     steps:
-    - uses: actions/checkout@v2
+    - uses: actions/checkout@v3
 
     - name: Install rustfmt
       run: |
@@ -39,7 +39,7 @@
               TARGET_TRIPLE: aarch64-unknown-linux-gnu
 
     steps:
-    - uses: actions/checkout@v2
+    - uses: actions/checkout@v3
 
     - name: Cache cargo installed crates
       uses: actions/cache@v2
@@ -127,7 +127,7 @@
     timeout-minutes: 60
 
     steps:
-    - uses: actions/checkout@v2
+    - uses: actions/checkout@v3
 
     #- name: Cache cargo installed crates
     #  uses: actions/cache@v2
diff --git a/compiler/rustc_codegen_cranelift/.github/workflows/nightly-cranelift.yml b/compiler/rustc_codegen_cranelift/.github/workflows/nightly-cranelift.yml
index a019793..0a3e7ca 100644
--- a/compiler/rustc_codegen_cranelift/.github/workflows/nightly-cranelift.yml
+++ b/compiler/rustc_codegen_cranelift/.github/workflows/nightly-cranelift.yml
@@ -11,7 +11,7 @@
     timeout-minutes: 60
 
     steps:
-    - uses: actions/checkout@v2
+    - uses: actions/checkout@v3
 
     - name: Cache cargo installed crates
       uses: actions/cache@v2
@@ -34,7 +34,7 @@
         sed -i 's/cranelift-jit = { version = "\w*.\w*.\w*", optional = true }/cranelift-jit = { git = "https:\/\/github.com\/bytecodealliance\/wasmtime.git", optional = true }/' Cargo.toml
         sed -i 's/cranelift-object = "\w*.\w*.\w*"/cranelift-object = { git = "https:\/\/github.com\/bytecodealliance\/wasmtime.git" }/' Cargo.toml
 
-        sed -i 's/gimli = { version = "0.25.0", default-features = false, features = \["write"\]}/gimli = { version = "0.26.1", default-features = false, features = ["write"] }/' Cargo.toml
+        sed -i 's/object = { version = "0.27.0"/object = { version = "0.28.0"/' Cargo.toml
 
         cat Cargo.toml
 
diff --git a/compiler/rustc_codegen_cranelift/.github/workflows/rustc.yml b/compiler/rustc_codegen_cranelift/.github/workflows/rustc.yml
index 1c08e5e..b8a98b8 100644
--- a/compiler/rustc_codegen_cranelift/.github/workflows/rustc.yml
+++ b/compiler/rustc_codegen_cranelift/.github/workflows/rustc.yml
@@ -8,7 +8,7 @@
     runs-on: ubuntu-latest
 
     steps:
-    - uses: actions/checkout@v2
+    - uses: actions/checkout@v3
 
     - name: Cache cargo installed crates
       uses: actions/cache@v2
@@ -46,7 +46,7 @@
     runs-on: ubuntu-latest
 
     steps:
-    - uses: actions/checkout@v2
+    - uses: actions/checkout@v3
 
     - name: Cache cargo installed crates
       uses: actions/cache@v2
diff --git a/compiler/rustc_codegen_cranelift/.vscode/settings.json b/compiler/rustc_codegen_cranelift/.vscode/settings.json
index 74fde9c..ecb20f2 100644
--- a/compiler/rustc_codegen_cranelift/.vscode/settings.json
+++ b/compiler/rustc_codegen_cranelift/.vscode/settings.json
@@ -5,7 +5,7 @@
     "rust-analyzer.assist.importEnforceGranularity": true,
     "rust-analyzer.assist.importPrefix": "crate",
     "rust-analyzer.cargo.runBuildScripts": true,
-    "rust-analyzer.cargo.features": ["unstable-features"]
+    "rust-analyzer.cargo.features": ["unstable-features"],
     "rust-analyzer.linkedProjects": [
         "./Cargo.toml",
         //"./build_sysroot/sysroot_src/src/libstd/Cargo.toml",
diff --git a/compiler/rustc_codegen_cranelift/Cargo.lock b/compiler/rustc_codegen_cranelift/Cargo.lock
index 7b8e43b..dac1cef 100644
--- a/compiler/rustc_codegen_cranelift/Cargo.lock
+++ b/compiler/rustc_codegen_cranelift/Cargo.lock
@@ -163,15 +163,15 @@
 
 [[package]]
 name = "hashbrown"
-version = "0.11.2"
+version = "0.12.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
+checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
 
 [[package]]
 name = "indexmap"
-version = "1.8.0"
+version = "1.9.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "282a6247722caba404c065016bbfa522806e51714c34f5dfc3e4a3a46fcb4223"
+checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e"
 dependencies = [
  "autocfg",
  "hashbrown",
diff --git a/compiler/rustc_codegen_cranelift/Cargo.toml b/compiler/rustc_codegen_cranelift/Cargo.toml
index 74f5080..781f26b 100644
--- a/compiler/rustc_codegen_cranelift/Cargo.toml
+++ b/compiler/rustc_codegen_cranelift/Cargo.toml
@@ -19,7 +19,7 @@
 object = { version = "0.27.0", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] }
 
 ar = { git = "https://github.com/bjorn3/rust-ar.git", branch = "do_not_remove_cg_clif_ranlib" }
-indexmap = "1.8.0"
+indexmap = "1.9.1"
 libloading = { version = "0.6.0", optional = true }
 once_cell = "1.10.0"
 smallvec = "1.6.1"
@@ -41,15 +41,5 @@
 jit = ["cranelift-jit", "libloading"]
 inline_asm = []
 
-# Disable optimizations and debuginfo of build scripts and some of the heavy build deps, as the
-# execution time of build scripts is so fast that optimizing them slows down the total build time.
-[profile.release.build-override]
-opt-level = 0
-debug = false
-
-[profile.release.package.cranelift-codegen-meta]
-opt-level = 0
-debug = false
-
 [package.metadata.rust-analyzer]
 rustc_private = true
diff --git a/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock b/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock
index 51ba0db..efee6ef 100644
--- a/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock
+++ b/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock
@@ -112,9 +112,9 @@
 
 [[package]]
 name = "hashbrown"
-version = "0.12.0"
+version = "0.12.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8c21d40587b92fa6a6c6e3c1bdbf87d75511db5672f9c93175574b3a00df1758"
+checksum = "db0d4cf898abf0081f964436dc980e96670a0f36863e4b83aaacdb65c9d7ccc3"
 dependencies = [
  "compiler_builtins",
  "rustc-std-workspace-alloc",
@@ -134,18 +134,18 @@
 
 [[package]]
 name = "libc"
-version = "0.2.124"
+version = "0.2.125"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "21a41fed9d98f27ab1c6d161da622a4fa35e8a54a8adc24bbf3ddd0ef70b0e50"
+checksum = "5916d2ae698f6de9bfb891ad7a8d65c09d232dc58cc4ac433c7da3b2fd84bc2b"
 dependencies = [
  "rustc-std-workspace-core",
 ]
 
 [[package]]
 name = "memchr"
-version = "2.4.1"
+version = "2.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
+checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
 dependencies = [
  "compiler_builtins",
  "rustc-std-workspace-core",
diff --git a/compiler/rustc_codegen_cranelift/build_system/build_backend.rs b/compiler/rustc_codegen_cranelift/build_system/build_backend.rs
index 0a56eb13..48faec8 100644
--- a/compiler/rustc_codegen_cranelift/build_system/build_backend.rs
+++ b/compiler/rustc_codegen_cranelift/build_system/build_backend.rs
@@ -34,18 +34,6 @@
         _ => unreachable!(),
     }
 
-    // Set the rpath to make the cg_clif executable find librustc_codegen_cranelift without changing
-    // LD_LIBRARY_PATH
-    if cfg!(unix) {
-        if cfg!(target_os = "macos") {
-            rustflags += " -Csplit-debuginfo=unpacked \
-                -Clink-arg=-Wl,-rpath,@loader_path/../lib \
-                -Zosx-rpath-install-name";
-        } else {
-            rustflags += " -Clink-arg=-Wl,-rpath=$ORIGIN/../lib ";
-        }
-    }
-
     cmd.env("RUSTFLAGS", rustflags);
 
     eprintln!("[BUILD] rustc_codegen_cranelift");
diff --git a/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs b/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs
index c9c003d..8682204 100644
--- a/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs
+++ b/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs
@@ -1,4 +1,3 @@
-use std::env;
 use std::fs;
 use std::path::{Path, PathBuf};
 use std::process::{self, Command};
@@ -22,35 +21,28 @@
     fs::create_dir_all(target_dir.join("lib")).unwrap();
 
     // Copy the backend
-    for file in ["cg_clif", "cg_clif_build_sysroot"] {
-        try_hard_link(
-            cg_clif_build_dir.join(get_file_name(file, "bin")),
-            target_dir.join("bin").join(get_file_name(file, "bin")),
-        );
-    }
-
     let cg_clif_dylib = get_file_name("rustc_codegen_cranelift", "dylib");
-    try_hard_link(
-        cg_clif_build_dir.join(&cg_clif_dylib),
-        target_dir
-            .join(if cfg!(windows) {
-                // Windows doesn't have rpath support, so the cg_clif dylib needs to be next to the
-                // binaries.
-                "bin"
-            } else {
-                "lib"
-            })
-            .join(cg_clif_dylib),
-    );
+    let cg_clif_dylib_path = target_dir
+        .join(if cfg!(windows) {
+            // Windows doesn't have rpath support, so the cg_clif dylib needs to be next to the
+            // binaries.
+            "bin"
+        } else {
+            "lib"
+        })
+        .join(&cg_clif_dylib);
+    try_hard_link(cg_clif_build_dir.join(cg_clif_dylib), &cg_clif_dylib_path);
 
-    // Build and copy cargo wrapper
-    let mut build_cargo_wrapper_cmd = Command::new("rustc");
-    build_cargo_wrapper_cmd
-        .arg("scripts/cargo-clif.rs")
-        .arg("-o")
-        .arg(target_dir.join("cargo-clif"))
-        .arg("-g");
-    spawn_and_wait(build_cargo_wrapper_cmd);
+    // Build and copy rustc and cargo wrappers
+    for wrapper in ["rustc-clif", "cargo-clif"] {
+        let mut build_cargo_wrapper_cmd = Command::new("rustc");
+        build_cargo_wrapper_cmd
+            .arg(PathBuf::from("scripts").join(format!("{wrapper}.rs")))
+            .arg("-o")
+            .arg(target_dir.join(wrapper))
+            .arg("-g");
+        spawn_and_wait(build_cargo_wrapper_cmd);
+    }
 
     let default_sysroot = super::rustc_info::get_default_sysroot();
 
@@ -117,7 +109,13 @@
             }
         }
         SysrootKind::Clif => {
-            build_clif_sysroot_for_triple(channel, target_dir, host_triple, None);
+            build_clif_sysroot_for_triple(
+                channel,
+                target_dir,
+                host_triple,
+                &cg_clif_dylib_path,
+                None,
+            );
 
             if host_triple != target_triple {
                 // When cross-compiling it is often necessary to manually pick the right linker
@@ -126,14 +124,21 @@
                 } else {
                     None
                 };
-                build_clif_sysroot_for_triple(channel, target_dir, target_triple, linker);
+                build_clif_sysroot_for_triple(
+                    channel,
+                    target_dir,
+                    target_triple,
+                    &cg_clif_dylib_path,
+                    linker,
+                );
             }
 
             // Copy std for the host to the lib dir. This is necessary for the jit mode to find
             // libstd.
             for file in fs::read_dir(host_rustlib_lib).unwrap() {
                 let file = file.unwrap().path();
-                if file.file_name().unwrap().to_str().unwrap().contains("std-") {
+                let filename = file.file_name().unwrap().to_str().unwrap();
+                if filename.contains("std-") && !filename.contains(".rlib") {
                     try_hard_link(&file, target_dir.join("lib").join(file.file_name().unwrap()));
                 }
             }
@@ -145,6 +150,7 @@
     channel: &str,
     target_dir: &Path,
     triple: &str,
+    cg_clif_dylib_path: &Path,
     linker: Option<&str>,
 ) {
     match fs::read_to_string(Path::new("build_sysroot").join("rustc_version")) {
@@ -168,18 +174,18 @@
     let build_dir = Path::new("build_sysroot").join("target").join(triple).join(channel);
 
     if !super::config::get_bool("keep_sysroot") {
-        // Cleanup the target dir with the exception of build scripts and the incremental cache
-        for dir in ["build", "deps", "examples", "native"] {
-            if build_dir.join(dir).exists() {
-                fs::remove_dir_all(build_dir.join(dir)).unwrap();
-            }
+        // Cleanup the deps dir, but keep build scripts and the incremental cache for faster
+        // recompilation as they are not affected by changes in cg_clif.
+        if build_dir.join("deps").exists() {
+            fs::remove_dir_all(build_dir.join("deps")).unwrap();
         }
     }
 
     // Build sysroot
     let mut build_cmd = Command::new("cargo");
     build_cmd.arg("build").arg("--target").arg(triple).current_dir("build_sysroot");
-    let mut rustflags = "--clif -Zforce-unstable-if-unmarked".to_string();
+    let mut rustflags = "-Zforce-unstable-if-unmarked -Cpanic=abort".to_string();
+    rustflags.push_str(&format!(" -Zcodegen-backend={}", cg_clif_dylib_path.to_str().unwrap()));
     if channel == "release" {
         build_cmd.arg("--release");
         rustflags.push_str(" -Zmir-opt-level=3");
@@ -189,10 +195,6 @@
         write!(rustflags, " -Clinker={}", linker).unwrap();
     }
     build_cmd.env("RUSTFLAGS", rustflags);
-    build_cmd.env(
-        "RUSTC",
-        env::current_dir().unwrap().join(target_dir).join("bin").join("cg_clif_build_sysroot"),
-    );
     build_cmd.env("__CARGO_DEFAULT_LIB_METADATA", "cg_clif");
     spawn_and_wait(build_cmd);
 
diff --git a/compiler/rustc_codegen_cranelift/build_system/mod.rs b/compiler/rustc_codegen_cranelift/build_system/mod.rs
index b228da3..b897b7f 100644
--- a/compiler/rustc_codegen_cranelift/build_system/mod.rs
+++ b/compiler/rustc_codegen_cranelift/build_system/mod.rs
@@ -86,6 +86,7 @@
             arg => arg_error!("Unexpected argument {}", arg),
         }
     }
+    target_dir = std::env::current_dir().unwrap().join(target_dir);
 
     let host_triple = if let Ok(host_triple) = std::env::var("HOST_TRIPLE") {
         host_triple
diff --git a/compiler/rustc_codegen_cranelift/docs/usage.md b/compiler/rustc_codegen_cranelift/docs/usage.md
index 785c738..33f146e 100644
--- a/compiler/rustc_codegen_cranelift/docs/usage.md
+++ b/compiler/rustc_codegen_cranelift/docs/usage.md
@@ -19,7 +19,7 @@
 > You should prefer using the Cargo method.
 
 ```bash
-$ $cg_clif_dir/build/bin/cg_clif my_crate.rs
+$ $cg_clif_dir/build/rustc-clif my_crate.rs
 ```
 
 ## Jit mode
@@ -38,7 +38,7 @@
 or
 
 ```bash
-$ $cg_clif_dir/build/bin/cg_clif -Zunstable-features -Cllvm-args=mode=jit -Cprefer-dynamic my_crate.rs
+$ $cg_clif_dir/build/rustc-clif -Zunstable-features -Cllvm-args=mode=jit -Cprefer-dynamic my_crate.rs
 ```
 
 There is also an experimental lazy jit mode. In this mode functions are only compiled once they are
@@ -54,7 +54,7 @@
 
 ```bash
 function jit_naked() {
-    echo "$@" | $cg_clif_dir/build/bin/cg_clif - -Zunstable-features -Cllvm-args=mode=jit -Cprefer-dynamic
+    echo "$@" | $cg_clif_dir/build/rustc-clif - -Zunstable-features -Cllvm-args=mode=jit -Cprefer-dynamic
 }
 
 function jit() {
diff --git a/compiler/rustc_codegen_cranelift/example/mini_core.rs b/compiler/rustc_codegen_cranelift/example/mini_core.rs
index 8da705e..489259d1 100644
--- a/compiler/rustc_codegen_cranelift/example/mini_core.rs
+++ b/compiler/rustc_codegen_cranelift/example/mini_core.rs
@@ -567,7 +567,7 @@
         pub fn copy<T>(src: *const T, dst: *mut T, count: usize);
         pub fn transmute<T, U>(e: T) -> U;
         pub fn ctlz_nonzero<T>(x: T) -> T;
-        pub fn needs_drop<T>() -> bool;
+        pub fn needs_drop<T: ?::Sized>() -> bool;
         pub fn bitreverse<T>(x: T) -> T;
         pub fn bswap<T>(x: T) -> T;
         pub fn write_bytes<T>(dst: *mut T, val: u8, count: usize);
diff --git a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs
index 85ca908..0f1245c 100644
--- a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs
+++ b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs
@@ -55,6 +55,11 @@
     inner: NoisyDropInner,
 }
 
+struct NoisyDropUnsized {
+    inner: NoisyDropInner,
+    text: str,
+}
+
 struct NoisyDropInner;
 
 impl Drop for NoisyDrop {
@@ -170,7 +175,9 @@
         assert_eq!(intrinsics::min_align_of_val(&a) as u8, intrinsics::min_align_of::<&str>() as u8);
 
         assert!(!intrinsics::needs_drop::<u8>());
+        assert!(!intrinsics::needs_drop::<[u8]>());
         assert!(intrinsics::needs_drop::<NoisyDrop>());
+        assert!(intrinsics::needs_drop::<NoisyDropUnsized>());
 
         Unique {
             pointer: NonNull(1 as *mut &str),
diff --git a/compiler/rustc_codegen_cranelift/patches/0027-sysroot-128bit-atomic-operations.patch b/compiler/rustc_codegen_cranelift/patches/0027-sysroot-128bit-atomic-operations.patch
index 8e6652a..ce1c6c9 100644
--- a/compiler/rustc_codegen_cranelift/patches/0027-sysroot-128bit-atomic-operations.patch
+++ b/compiler/rustc_codegen_cranelift/patches/0027-sysroot-128bit-atomic-operations.patch
@@ -21,7 +21,7 @@
 -#[cfg(target_has_atomic_load_store = "128")]
 -#[unstable(feature = "integer_atomics", issue = "32976")]
 -impl RefUnwindSafe for crate::sync::atomic::AtomicI128 {}
- 
+
  #[cfg(target_has_atomic_load_store = "ptr")]
  #[stable(feature = "unwind_safe_atomic_refs", since = "1.14.0")]
 @@ -235,9 +232,6 @@ impl RefUnwindSafe for crate::sync::atomic::AtomicU32 {}
@@ -31,14 +31,14 @@
 -#[cfg(target_has_atomic_load_store = "128")]
 -#[unstable(feature = "integer_atomics", issue = "32976")]
 -impl RefUnwindSafe for crate::sync::atomic::AtomicU128 {}
- 
+
  #[cfg(target_has_atomic_load_store = "8")]
  #[stable(feature = "unwind_safe_atomic_refs", since = "1.14.0")]
 diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs
 index d9de37e..8293fce 100644
 --- a/library/core/src/sync/atomic.rs
 +++ b/library/core/src/sync/atomic.rs
-@@ -2234,44 +2234,6 @@ atomic_int! {
+@@ -2234,46 +2234,6 @@ atomic_int! {
      "AtomicU64::new(0)",
      u64 AtomicU64 ATOMIC_U64_INIT
  }
@@ -54,6 +54,7 @@
 -    unstable(feature = "integer_atomics", issue = "32976"),
 -    rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
 -    unstable(feature = "integer_atomics", issue = "32976"),
+-    cfg_attr(not(test), rustc_diagnostic_item = "AtomicI128"),
 -    "i128",
 -    "#![feature(integer_atomics)]\n\n",
 -    atomic_min, atomic_max,
@@ -73,6 +74,7 @@
 -    unstable(feature = "integer_atomics", issue = "32976"),
 -    rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
 -    unstable(feature = "integer_atomics", issue = "32976"),
+-    cfg_attr(not(test), rustc_diagnostic_item = "AtomicU128"),
 -    "u128",
 -    "#![feature(integer_atomics)]\n\n",
 -    atomic_umin, atomic_umax,
@@ -98,6 +100,6 @@
      #[cfg(target_has_atomic = "ptr")]
      assert_eq!(align_of::<AtomicUsize>(), size_of::<AtomicUsize>());
      #[cfg(target_has_atomic = "ptr")]
--- 
+--
 2.26.2.7.g19db9cfb68
 
diff --git a/compiler/rustc_codegen_cranelift/rust-toolchain b/compiler/rustc_codegen_cranelift/rust-toolchain
index 966097c..e98e92e 100644
--- a/compiler/rustc_codegen_cranelift/rust-toolchain
+++ b/compiler/rustc_codegen_cranelift/rust-toolchain
@@ -1,3 +1,3 @@
 [toolchain]
-channel = "nightly-2022-04-21"
+channel = "nightly-2022-05-15"
 components = ["rust-src", "rustc-dev", "llvm-tools-preview"]
diff --git a/compiler/rustc_codegen_cranelift/scripts/cargo-clif.rs b/compiler/rustc_codegen_cranelift/scripts/cargo-clif.rs
index 41d82b5..9362b47 100644
--- a/compiler/rustc_codegen_cranelift/scripts/cargo-clif.rs
+++ b/compiler/rustc_codegen_cranelift/scripts/cargo-clif.rs
@@ -5,20 +5,11 @@
 use std::process::Command;
 
 fn main() {
-    if env::var("RUSTC_WRAPPER").map_or(false, |wrapper| wrapper.contains("sccache")) {
-        eprintln!(
-            "\x1b[1;93m=== Warning: Unsetting RUSTC_WRAPPER to prevent interference with sccache ===\x1b[0m"
-        );
-        env::remove_var("RUSTC_WRAPPER");
-    }
-
     let sysroot = PathBuf::from(env::current_exe().unwrap().parent().unwrap());
 
-    env::set_var("RUSTC", sysroot.join("bin/cg_clif".to_string() + env::consts::EXE_SUFFIX));
-
-    let mut rustdoc_flags = env::var("RUSTDOCFLAGS").unwrap_or(String::new());
-    rustdoc_flags.push_str(" -Cpanic=abort -Zpanic-abort-tests -Zcodegen-backend=");
-    rustdoc_flags.push_str(
+    let mut rustflags = String::new();
+    rustflags.push_str(" -Cpanic=abort -Zpanic-abort-tests -Zcodegen-backend=");
+    rustflags.push_str(
         sysroot
             .join(if cfg!(windows) { "bin" } else { "lib" })
             .join(
@@ -29,9 +20,10 @@
             .to_str()
             .unwrap(),
     );
-    rustdoc_flags.push_str(" --sysroot ");
-    rustdoc_flags.push_str(sysroot.to_str().unwrap());
-    env::set_var("RUSTDOCFLAGS", rustdoc_flags);
+    rustflags.push_str(" --sysroot ");
+    rustflags.push_str(sysroot.to_str().unwrap());
+    env::set_var("RUSTFLAGS", env::var("RUSTFLAGS").unwrap_or(String::new()) + &rustflags);
+    env::set_var("RUSTDOCFLAGS", env::var("RUSTDOCFLAGS").unwrap_or(String::new()) + &rustflags);
 
     // Ensure that the right toolchain is used
     env::set_var("RUSTUP_TOOLCHAIN", env!("RUSTUP_TOOLCHAIN"));
@@ -46,7 +38,7 @@
                 .chain(env::args().skip(2))
                 .chain([
                     "--".to_string(),
-                    "-Zunstable-features".to_string(),
+                    "-Zunstable-options".to_string(),
                     "-Cllvm-args=mode=jit".to_string(),
                 ])
                 .collect()
@@ -60,7 +52,7 @@
                 .chain(env::args().skip(2))
                 .chain([
                     "--".to_string(),
-                    "-Zunstable-features".to_string(),
+                    "-Zunstable-options".to_string(),
                     "-Cllvm-args=mode=jit-lazy".to_string(),
                 ])
                 .collect()
diff --git a/compiler/rustc_codegen_cranelift/scripts/config.sh b/compiler/rustc_codegen_cranelift/scripts/config.sh
deleted file mode 100644
index 53ada36..0000000
--- a/compiler/rustc_codegen_cranelift/scripts/config.sh
+++ /dev/null
@@ -1,6 +0,0 @@
-# Note to people running shellcheck: this file should only be sourced, not executed directly.
-
-set -e
-
-export LD_LIBRARY_PATH="$(rustc --print sysroot)/lib:$LD_LIBRARY_PATH"
-export DYLD_LIBRARY_PATH="$(rustc --print sysroot)/lib:$DYLD_LIBRARY_PATH"
diff --git a/compiler/rustc_codegen_cranelift/scripts/ext_config.sh b/compiler/rustc_codegen_cranelift/scripts/ext_config.sh
deleted file mode 100644
index 11d6c4c..0000000
--- a/compiler/rustc_codegen_cranelift/scripts/ext_config.sh
+++ /dev/null
@@ -1,32 +0,0 @@
-# Note to people running shellcheck: this file should only be sourced, not executed directly.
-
-# Various env vars that should only be set for the build system
-
-set -e
-
-export CG_CLIF_DISPLAY_CG_TIME=1
-export CG_CLIF_DISABLE_INCR_CACHE=1
-
-export HOST_TRIPLE=$(rustc -vV | grep host | cut -d: -f2 | tr -d " ")
-export TARGET_TRIPLE=${TARGET_TRIPLE:-$HOST_TRIPLE}
-
-export RUN_WRAPPER=''
-export JIT_SUPPORTED=1
-if [[ "$HOST_TRIPLE" != "$TARGET_TRIPLE" ]]; then
-   export JIT_SUPPORTED=0
-   if [[ "$TARGET_TRIPLE" == "aarch64-unknown-linux-gnu" ]]; then
-      # We are cross-compiling for aarch64. Use the correct linker and run tests in qemu.
-      export RUSTFLAGS='-Clinker=aarch64-linux-gnu-gcc '$RUSTFLAGS
-      export RUN_WRAPPER='qemu-aarch64 -L /usr/aarch64-linux-gnu'
-   elif [[ "$TARGET_TRIPLE" == "x86_64-pc-windows-gnu" ]]; then
-      # We are cross-compiling for Windows. Run tests in wine.
-      export RUN_WRAPPER='wine'
-   else
-      echo "Unknown non-native platform"
-   fi
-fi
-
-# FIXME fix `#[linkage = "extern_weak"]` without this
-if [[ "$(uname)" == 'Darwin' ]]; then
-   export RUSTFLAGS="$RUSTFLAGS -Clink-arg=-undefined -Clink-arg=dynamic_lookup"
-fi
diff --git a/compiler/rustc_codegen_cranelift/scripts/filter_profile.rs b/compiler/rustc_codegen_cranelift/scripts/filter_profile.rs
index f4e863e..e6f60d1 100755
--- a/compiler/rustc_codegen_cranelift/scripts/filter_profile.rs
+++ b/compiler/rustc_codegen_cranelift/scripts/filter_profile.rs
@@ -2,8 +2,7 @@
 #![forbid(unsafe_code)]/* This line is ignored by bash
 # This block is ignored by rustc
 pushd $(dirname "$0")/../
-source scripts/config.sh
-RUSTC="$(pwd)/build/bin/cg_clif"
+RUSTC="$(pwd)/build/rustc-clif"
 popd
 PROFILE=$1 OUTPUT=$2 exec $RUSTC -Zunstable-options -Cllvm-args=mode=jit -Cprefer-dynamic $0
 #*/
diff --git a/compiler/rustc_codegen_cranelift/scripts/rustc-clif.rs b/compiler/rustc_codegen_cranelift/scripts/rustc-clif.rs
new file mode 100644
index 0000000..3abfcd8
--- /dev/null
+++ b/compiler/rustc_codegen_cranelift/scripts/rustc-clif.rs
@@ -0,0 +1,36 @@
+use std::env;
+use std::ffi::OsString;
+#[cfg(unix)]
+use std::os::unix::process::CommandExt;
+use std::path::PathBuf;
+use std::process::Command;
+
+fn main() {
+    let sysroot = PathBuf::from(env::current_exe().unwrap().parent().unwrap());
+
+    let cg_clif_dylib_path = sysroot.join(if cfg!(windows) { "bin" } else { "lib" }).join(
+        env::consts::DLL_PREFIX.to_string() + "rustc_codegen_cranelift" + env::consts::DLL_SUFFIX,
+    );
+
+    let mut args = std::env::args_os().skip(1).collect::<Vec<_>>();
+    args.push(OsString::from("-Cpanic=abort"));
+    args.push(OsString::from("-Zpanic-abort-tests"));
+    let mut codegen_backend_arg = OsString::from("-Zcodegen-backend=");
+    codegen_backend_arg.push(cg_clif_dylib_path);
+    args.push(codegen_backend_arg);
+    if !args.contains(&OsString::from("--sysroot")) {
+        args.push(OsString::from("--sysroot"));
+        args.push(OsString::from(sysroot.to_str().unwrap()));
+    }
+
+    // Ensure that the right toolchain is used
+    env::set_var("RUSTUP_TOOLCHAIN", env!("RUSTUP_TOOLCHAIN"));
+
+    #[cfg(unix)]
+    Command::new("rustc").args(args).exec();
+
+    #[cfg(not(unix))]
+    std::process::exit(
+        Command::new("rustc").args(args).spawn().unwrap().wait().unwrap().code().unwrap_or(1),
+    );
+}
diff --git a/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh b/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh
index cabbaaa..4d0dfa1 100644
--- a/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh
+++ b/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh
@@ -2,7 +2,6 @@
 set -e
 
 ./y.rs build --no-unstable-features
-source scripts/config.sh
 
 echo "[SETUP] Rust fork"
 git clone https://github.com/rust-lang/rust.git || true
@@ -26,21 +25,6 @@
  [dev-dependencies]
  rand = "0.7"
  rand_xorshift = "0.2"
-diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs
-index 887d27fd6dca4..2c2239f2b83d1 100644
---- a/src/tools/compiletest/src/header.rs
-+++ b/src/tools/compiletest/src/header.rs
-@@ -806,8 +806,8 @@ pub fn make_test_description<R: Read>(
-     cfg: Option<&str>,
- ) -> test::TestDesc {
-     let mut ignore = false;
-     #[cfg(not(bootstrap))]
--    let ignore_message: Option<String> = None;
-+    let ignore_message: Option<&str> = None;
-     let mut should_fail = false;
-
-     let rustc_has_profiler_support = env::var_os("RUSTC_PROFILER_SUPPORT").is_some();
-
 diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
 index 8431aa7b818..a3ff7e68ce5 100644
 --- a/src/tools/compiletest/src/runtest.rs
@@ -67,7 +51,7 @@
 ninja = false
 
 [build]
-rustc = "$(pwd)/../build/bin/cg_clif"
+rustc = "$(pwd)/../build/rustc-clif"
 cargo = "$(rustup which cargo)"
 full-bootstrap = true
 local-rebuild = true
diff --git a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh
index 4cf24c0..9bdb9f2 100755
--- a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh
+++ b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh
@@ -101,11 +101,10 @@
 rm src/test/incremental/spike-neg2.rs # same
 rm src/test/ui/issues/issue-74564-if-expr-stack-overflow.rs # gives a stackoverflow before the backend runs
 rm src/test/ui/mir/ssa-analysis-regression-50041.rs # produces ICE
+rm src/test/ui/type-alias-impl-trait/assoc-projection-ice.rs # produces ICE
 
 rm src/test/ui/simd/intrinsic/generic-reduction-pass.rs # simd_reduce_add_unordered doesn't accept an accumulator for integer vectors
 
-rm src/test/ui/rfc-2091-track-caller/intrinsic-wrapper.rs # wrong result from `Location::caller()`
-
 # bugs in the test suite
 # ======================
 rm src/test/ui/backtrace.rs # TODO warning
diff --git a/compiler/rustc_codegen_cranelift/scripts/tests.sh b/compiler/rustc_codegen_cranelift/scripts/tests.sh
index aae6260..9b5ffa4 100755
--- a/compiler/rustc_codegen_cranelift/scripts/tests.sh
+++ b/compiler/rustc_codegen_cranelift/scripts/tests.sh
@@ -2,10 +2,43 @@
 
 set -e
 
-source scripts/config.sh
-source scripts/ext_config.sh
-export RUSTC=false # ensure that cg_llvm isn't accidentally used
-MY_RUSTC="$(pwd)/build/bin/cg_clif $RUSTFLAGS -L crate=target/out --out-dir target/out -Cdebuginfo=2"
+export CG_CLIF_DISPLAY_CG_TIME=1
+export CG_CLIF_DISABLE_INCR_CACHE=1
+
+export HOST_TRIPLE=$(rustc -vV | grep host | cut -d: -f2 | tr -d " ")
+export TARGET_TRIPLE=${TARGET_TRIPLE:-$HOST_TRIPLE}
+
+export RUN_WRAPPER=''
+
+case "$TARGET_TRIPLE" in
+   x86_64*)
+      export JIT_SUPPORTED=1
+      ;;
+   *)
+      export JIT_SUPPORTED=0
+      ;;
+esac
+
+if [[ "$HOST_TRIPLE" != "$TARGET_TRIPLE" ]]; then
+   export JIT_SUPPORTED=0
+   if [[ "$TARGET_TRIPLE" == "aarch64-unknown-linux-gnu" ]]; then
+      # We are cross-compiling for aarch64. Use the correct linker and run tests in qemu.
+      export RUSTFLAGS='-Clinker=aarch64-linux-gnu-gcc '$RUSTFLAGS
+      export RUN_WRAPPER='qemu-aarch64 -L /usr/aarch64-linux-gnu'
+   elif [[ "$TARGET_TRIPLE" == "x86_64-pc-windows-gnu" ]]; then
+      # We are cross-compiling for Windows. Run tests in wine.
+      export RUN_WRAPPER='wine'
+   else
+      echo "Unknown non-native platform"
+   fi
+fi
+
+# FIXME fix `#[linkage = "extern_weak"]` without this
+if [[ "$(uname)" == 'Darwin' ]]; then
+   export RUSTFLAGS="$RUSTFLAGS -Clink-arg=-undefined -Clink-arg=dynamic_lookup"
+fi
+
+MY_RUSTC="$(pwd)/build/rustc-clif $RUSTFLAGS -L crate=target/out --out-dir target/out -Cdebuginfo=2"
 
 function no_sysroot_tests() {
     echo "[BUILD] mini_core"
@@ -39,7 +72,7 @@
     $MY_RUSTC example/issue-91827-extern-types.rs --crate-name issue_91827_extern_types --crate-type bin --target "$TARGET_TRIPLE"
     $RUN_WRAPPER ./target/out/issue_91827_extern_types
 
-    echo "[AOT] alloc_system"
+    echo "[BUILD] alloc_system"
     $MY_RUSTC example/alloc_system.rs --crate-type lib --target "$TARGET_TRIPLE"
 
     echo "[AOT] alloc_example"
@@ -56,14 +89,14 @@
         echo "[JIT] std_example (skipped)"
     fi
 
-    echo "[AOT] dst_field_align"
-    $MY_RUSTC example/dst-field-align.rs --crate-name dst_field_align --crate-type bin --target "$TARGET_TRIPLE"
-    $RUN_WRAPPER ./target/out/dst_field_align || (echo $?; false)
-
     echo "[AOT] std_example"
     $MY_RUSTC example/std_example.rs --crate-type bin --target "$TARGET_TRIPLE"
     $RUN_WRAPPER ./target/out/std_example arg
 
+    echo "[AOT] dst_field_align"
+    $MY_RUSTC example/dst-field-align.rs --crate-name dst_field_align --crate-type bin --target "$TARGET_TRIPLE"
+    $RUN_WRAPPER ./target/out/dst_field_align
+
     echo "[AOT] subslice-patterns-const-eval"
     $MY_RUSTC example/subslice-patterns-const-eval.rs --crate-type bin -Cpanic=abort --target "$TARGET_TRIPLE"
     $RUN_WRAPPER ./target/out/subslice-patterns-const-eval
@@ -97,7 +130,7 @@
     if [[ "$HOST_TRIPLE" = "$TARGET_TRIPLE" ]]; then
         echo "[BENCH COMPILE] ebobby/simple-raytracer"
         hyperfine --runs "${RUN_RUNS:-10}" --warmup 1 --prepare "../build/cargo-clif clean" \
-        "RUSTC=rustc RUSTFLAGS='' cargo build" \
+        "RUSTFLAGS='' cargo build" \
         "../build/cargo-clif build"
 
         echo "[BENCH RUN] ebobby/simple-raytracer"
diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs
index ef56fb1..ffa5d74 100644
--- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs
@@ -23,6 +23,7 @@
 ) -> Signature {
     let call_conv = match fn_abi.conv {
         Conv::Rust | Conv::C => default_call_conv,
+        Conv::RustCold => CallConv::Cold,
         Conv::X86_64SysV => CallConv::SystemV,
         Conv::X86_64Win64 => CallConv::WindowsFastcall,
         Conv::ArmAapcs
@@ -309,16 +310,17 @@
 
 pub(crate) fn codegen_terminator_call<'tcx>(
     fx: &mut FunctionCx<'_, '_, 'tcx>,
-    span: Span,
+    source_info: mir::SourceInfo,
     func: &Operand<'tcx>,
     args: &[Operand<'tcx>],
-    mir_dest: Option<(Place<'tcx>, BasicBlock)>,
+    destination: Place<'tcx>,
+    target: Option<BasicBlock>,
 ) {
     let fn_ty = fx.monomorphize(func.ty(fx.mir, fx.tcx));
     let fn_sig =
         fx.tcx.normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), fn_ty.fn_sig(fx.tcx));
 
-    let destination = mir_dest.map(|(place, bb)| (codegen_place(fx, place), bb));
+    let ret_place = codegen_place(fx, destination);
 
     // Handle special calls like instrinsics and empty drop glue.
     let instance = if let ty::FnDef(def_id, substs) = *fn_ty.kind() {
@@ -333,19 +335,27 @@
                 &fx.tcx.symbol_name(instance).name,
                 substs,
                 args,
-                destination,
+                ret_place,
+                target,
             );
             return;
         }
 
         match instance.def {
             InstanceDef::Intrinsic(_) => {
-                crate::intrinsics::codegen_intrinsic_call(fx, instance, args, destination, span);
+                crate::intrinsics::codegen_intrinsic_call(
+                    fx,
+                    instance,
+                    args,
+                    ret_place,
+                    target,
+                    source_info,
+                );
                 return;
             }
             InstanceDef::DropGlue(_, None) => {
                 // empty drop glue - a nop.
-                let (_, dest) = destination.expect("Non terminating drop_in_place_real???");
+                let dest = target.expect("Non terminating drop_in_place_real???");
                 let ret_block = fx.get_block(dest);
                 fx.bcx.ins().jump(ret_block, &[]);
                 return;
@@ -371,7 +381,7 @@
         .unwrap_or(false);
     if is_cold {
         fx.bcx.set_cold_block(fx.bcx.current_block().unwrap());
-        if let Some((_place, destination_block)) = destination {
+        if let Some(destination_block) = target {
             fx.bcx.set_cold_block(fx.get_block(destination_block));
         }
     }
@@ -402,7 +412,7 @@
 
     // Pass the caller location for `#[track_caller]`.
     if instance.map(|inst| inst.def.requires_caller_location(fx.tcx)).unwrap_or(false) {
-        let caller_location = fx.get_caller_location(span);
+        let caller_location = fx.get_caller_location(source_info);
         args.push(CallArgument { value: caller_location, is_owned: false });
     }
 
@@ -453,7 +463,6 @@
         }
     };
 
-    let ret_place = destination.map(|(place, _)| place);
     self::returning::codegen_with_call_return_arg(fx, &fn_abi.ret, ret_place, |fx, return_ptr| {
         let call_args = return_ptr
             .into_iter()
@@ -479,9 +488,10 @@
         // FIXME find a cleaner way to support varargs
         if fn_sig.c_variadic {
             if !matches!(fn_sig.abi, Abi::C { .. }) {
-                fx.tcx
-                    .sess
-                    .span_fatal(span, &format!("Variadic call for non-C abi {:?}", fn_sig.abi));
+                fx.tcx.sess.span_fatal(
+                    source_info.span,
+                    &format!("Variadic call for non-C abi {:?}", fn_sig.abi),
+                );
             }
             let sig_ref = fx.bcx.func.dfg.call_signature(call_inst).unwrap();
             let abi_params = call_args
@@ -490,9 +500,10 @@
                     let ty = fx.bcx.func.dfg.value_type(arg);
                     if !ty.is_int() {
                         // FIXME set %al to upperbound on float args once floats are supported
-                        fx.tcx
-                            .sess
-                            .span_fatal(span, &format!("Non int ty {:?} for variadic call", ty));
+                        fx.tcx.sess.span_fatal(
+                            source_info.span,
+                            &format!("Non int ty {:?} for variadic call", ty),
+                        );
                     }
                     AbiParam::new(ty)
                 })
@@ -503,7 +514,7 @@
         call_inst
     });
 
-    if let Some((_, dest)) = destination {
+    if let Some(dest) = target {
         let ret_block = fx.get_block(dest);
         fx.bcx.ins().jump(ret_block, &[]);
     } else {
@@ -513,7 +524,7 @@
 
 pub(crate) fn codegen_drop<'tcx>(
     fx: &mut FunctionCx<'_, '_, 'tcx>,
-    span: Span,
+    source_info: mir::SourceInfo,
     drop_place: CPlace<'tcx>,
 ) {
     let ty = drop_place.layout().ty;
@@ -560,7 +571,7 @@
 
                 if drop_instance.def.requires_caller_location(fx.tcx) {
                     // Pass the caller location for `#[track_caller]`.
-                    let caller_location = fx.get_caller_location(span);
+                    let caller_location = fx.get_caller_location(source_info);
                     call_args.extend(
                         adjust_arg_for_abi(fx, caller_location, &fn_abi.args[1], false).into_iter(),
                     );
diff --git a/compiler/rustc_codegen_cranelift/src/abi/returning.rs b/compiler/rustc_codegen_cranelift/src/abi/returning.rs
index c1bdba4..ff3bb2d 100644
--- a/compiler/rustc_codegen_cranelift/src/abi/returning.rs
+++ b/compiler/rustc_codegen_cranelift/src/abi/returning.rs
@@ -56,23 +56,22 @@
 pub(super) fn codegen_with_call_return_arg<'tcx>(
     fx: &mut FunctionCx<'_, '_, 'tcx>,
     ret_arg_abi: &ArgAbi<'tcx, Ty<'tcx>>,
-    ret_place: Option<CPlace<'tcx>>,
+    ret_place: CPlace<'tcx>,
     f: impl FnOnce(&mut FunctionCx<'_, '_, 'tcx>, Option<Value>) -> Inst,
 ) {
     let (ret_temp_place, return_ptr) = match ret_arg_abi.mode {
         PassMode::Ignore => (None, None),
-        PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } => match ret_place {
-            Some(ret_place) if matches!(ret_place.inner(), CPlaceInner::Addr(_, None)) => {
+        PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } => {
+            if matches!(ret_place.inner(), CPlaceInner::Addr(_, None)) {
                 // This is an optimization to prevent unnecessary copies of the return value when
                 // the return place is already a memory place as opposed to a register.
                 // This match arm can be safely removed.
                 (None, Some(ret_place.to_ptr().get_addr(fx)))
-            }
-            _ => {
+            } else {
                 let place = CPlace::new_stack_slot(fx, ret_arg_abi.layout);
                 (Some(place), Some(place.to_ptr().get_addr(fx)))
             }
-        },
+        }
         PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => {
             unreachable!("unsized return value")
         }
@@ -84,39 +83,25 @@
     match ret_arg_abi.mode {
         PassMode::Ignore => {}
         PassMode::Direct(_) => {
-            if let Some(ret_place) = ret_place {
-                let ret_val = fx.bcx.inst_results(call_inst)[0];
-                ret_place.write_cvalue(fx, CValue::by_val(ret_val, ret_arg_abi.layout));
-            }
+            let ret_val = fx.bcx.inst_results(call_inst)[0];
+            ret_place.write_cvalue(fx, CValue::by_val(ret_val, ret_arg_abi.layout));
         }
         PassMode::Pair(_, _) => {
-            if let Some(ret_place) = ret_place {
-                let ret_val_a = fx.bcx.inst_results(call_inst)[0];
-                let ret_val_b = fx.bcx.inst_results(call_inst)[1];
-                ret_place.write_cvalue(
-                    fx,
-                    CValue::by_val_pair(ret_val_a, ret_val_b, ret_arg_abi.layout),
-                );
-            }
+            let ret_val_a = fx.bcx.inst_results(call_inst)[0];
+            let ret_val_b = fx.bcx.inst_results(call_inst)[1];
+            ret_place
+                .write_cvalue(fx, CValue::by_val_pair(ret_val_a, ret_val_b, ret_arg_abi.layout));
         }
         PassMode::Cast(cast) => {
-            if let Some(ret_place) = ret_place {
-                let results = fx
-                    .bcx
-                    .inst_results(call_inst)
-                    .iter()
-                    .copied()
-                    .collect::<SmallVec<[Value; 2]>>();
-                let result =
-                    super::pass_mode::from_casted_value(fx, &results, ret_place.layout(), cast);
-                ret_place.write_cvalue(fx, result);
-            }
+            let results =
+                fx.bcx.inst_results(call_inst).iter().copied().collect::<SmallVec<[Value; 2]>>();
+            let result =
+                super::pass_mode::from_casted_value(fx, &results, ret_place.layout(), cast);
+            ret_place.write_cvalue(fx, result);
         }
         PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } => {
-            if let (Some(ret_place), Some(ret_temp_place)) = (ret_place, ret_temp_place) {
-                // Both ret_place and ret_temp_place must be Some. If ret_place is None, this is
-                // a non-returning call. If ret_temp_place is None, it is not necessary to copy the
-                // return value.
+            if let Some(ret_temp_place) = ret_temp_place {
+                // If ret_temp_place is None, it is not necessary to copy the return value.
                 let ret_temp_value = ret_temp_place.to_cvalue(fx);
                 ret_place.write_cvalue(fx, ret_temp_value);
             }
diff --git a/compiler/rustc_codegen_cranelift/src/archive.rs b/compiler/rustc_codegen_cranelift/src/archive.rs
index a099e8b..0812f93 100644
--- a/compiler/rustc_codegen_cranelift/src/archive.rs
+++ b/compiler/rustc_codegen_cranelift/src/archive.rs
@@ -30,25 +30,7 @@
 }
 
 impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> {
-    fn new(sess: &'a Session, output: &Path, input: Option<&Path>) -> Self {
-        let (src_archives, entries) = if let Some(input) = input {
-            let read_cache = ReadCache::new(File::open(input).unwrap());
-            let archive = ArchiveFile::parse(&read_cache).unwrap();
-            let mut entries = Vec::new();
-
-            for entry in archive.members() {
-                let entry = entry.unwrap();
-                entries.push((
-                    entry.name().to_vec(),
-                    ArchiveEntry::FromArchive { archive_index: 0, file_range: entry.file_range() },
-                ));
-            }
-
-            (vec![read_cache.into_inner()], entries)
-        } else {
-            (vec![], Vec::new())
-        };
-
+    fn new(sess: &'a Session, output: &Path) -> Self {
         ArArchiveBuilder {
             sess,
             dst: output.to_path_buf(),
@@ -56,24 +38,11 @@
             // FIXME fix builtin ranlib on macOS
             no_builtin_ranlib: sess.target.is_like_osx,
 
-            src_archives,
-            entries,
+            src_archives: vec![],
+            entries: vec![],
         }
     }
 
-    fn src_files(&mut self) -> Vec<String> {
-        self.entries.iter().map(|(name, _)| String::from_utf8(name.clone()).unwrap()).collect()
-    }
-
-    fn remove_file(&mut self, name: &str) {
-        let index = self
-            .entries
-            .iter()
-            .position(|(entry_name, _)| entry_name == name.as_bytes())
-            .expect("Tried to remove file not existing in src archive");
-        self.entries.remove(index);
-    }
-
     fn add_file(&mut self, file: &Path) {
         self.entries.push((
             file.file_name().unwrap().to_str().unwrap().to_string().into_bytes(),
@@ -105,7 +74,7 @@
         Ok(())
     }
 
-    fn build(mut self) {
+    fn build(mut self) -> bool {
         enum BuilderKind {
             Bsd(ar::Builder<File>),
             Gnu(ar::GnuBuilder<File>),
@@ -204,6 +173,8 @@
             )
         };
 
+        let any_members = !entries.is_empty();
+
         // Add all files
         for (entry_name, data) in entries.into_iter() {
             let header = ar::Header::new(entry_name, data.len() as u64);
@@ -229,6 +200,8 @@
                 self.sess.fatal(&format!("Ranlib exited with code {:?}", status.code()));
             }
         }
+
+        any_members
     }
 
     fn inject_dll_import_lib(
diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs
index 65346cb..fbe830b 100644
--- a/compiler/rustc_codegen_cranelift/src/base.rs
+++ b/compiler/rustc_codegen_cranelift/src/base.rs
@@ -325,7 +325,7 @@
                     AssertKind::BoundsCheck { ref len, ref index } => {
                         let len = codegen_operand(fx, len).load_scalar(fx);
                         let index = codegen_operand(fx, index).load_scalar(fx);
-                        let location = fx.get_caller_location(source_info.span).load_scalar(fx);
+                        let location = fx.get_caller_location(source_info).load_scalar(fx);
 
                         codegen_panic_inner(
                             fx,
@@ -336,7 +336,7 @@
                     }
                     _ => {
                         let msg_str = msg.description();
-                        codegen_panic(fx, msg_str, source_info.span);
+                        codegen_panic(fx, msg_str, source_info);
                     }
                 }
             }
@@ -393,12 +393,20 @@
                 func,
                 args,
                 destination,
+                target,
                 fn_span,
                 cleanup: _,
                 from_hir_call: _,
             } => {
                 fx.tcx.sess.time("codegen call", || {
-                    crate::abi::codegen_terminator_call(fx, *fn_span, func, args, *destination)
+                    crate::abi::codegen_terminator_call(
+                        fx,
+                        mir::SourceInfo { span: *fn_span, ..source_info },
+                        func,
+                        args,
+                        *destination,
+                        *target,
+                    )
                 });
             }
             TerminatorKind::InlineAsm {
@@ -450,7 +458,7 @@
             }
             TerminatorKind::Drop { place, target, unwind: _ } => {
                 let drop_place = codegen_place(fx, *place);
-                crate::abi::codegen_drop(fx, source_info.span, drop_place);
+                crate::abi::codegen_drop(fx, source_info, drop_place);
 
                 let target_block = fx.get_block(*target);
                 fx.bcx.ins().jump(target_block, &[]);
@@ -471,7 +479,7 @@
 
     fx.set_debug_loc(stmt.source_info);
 
-    #[cfg(disabled)]
+    #[cfg(any())] // This is never true
     match &stmt.kind {
         StatementKind::StorageLive(..) | StatementKind::StorageDead(..) => {} // Those are not very useful
         _ => {
@@ -599,7 +607,13 @@
                     let operand = codegen_operand(fx, operand);
                     lval.write_cvalue(fx, operand.cast_pointer_to(to_layout));
                 }
-                Rvalue::Cast(CastKind::Misc, ref operand, to_ty) => {
+                Rvalue::Cast(
+                    CastKind::Misc
+                    | CastKind::PointerExposeAddress
+                    | CastKind::PointerFromExposedAddress,
+                    ref operand,
+                    to_ty,
+                ) => {
                     let operand = codegen_operand(fx, operand);
                     let from_ty = operand.layout().ty;
                     let to_ty = fx.monomorphize(to_ty);
@@ -696,7 +710,7 @@
                     let times = fx
                         .monomorphize(times)
                         .eval(fx.tcx, ParamEnv::reveal_all())
-                        .val()
+                        .kind()
                         .try_to_bits(fx.tcx.data_layout.pointer_size)
                         .unwrap();
                     if operand.layout().size.bytes() == 0 {
@@ -898,14 +912,18 @@
     }
 }
 
-pub(crate) fn codegen_panic<'tcx>(fx: &mut FunctionCx<'_, '_, 'tcx>, msg_str: &str, span: Span) {
-    let location = fx.get_caller_location(span).load_scalar(fx);
+pub(crate) fn codegen_panic<'tcx>(
+    fx: &mut FunctionCx<'_, '_, 'tcx>,
+    msg_str: &str,
+    source_info: mir::SourceInfo,
+) {
+    let location = fx.get_caller_location(source_info).load_scalar(fx);
 
     let msg_ptr = fx.anonymous_str(msg_str);
     let msg_len = fx.bcx.ins().iconst(fx.pointer_type, i64::try_from(msg_str.len()).unwrap());
     let args = [msg_ptr, msg_len, location];
 
-    codegen_panic_inner(fx, rustc_hir::LangItem::Panic, &args, span);
+    codegen_panic_inner(fx, rustc_hir::LangItem::Panic, &args, source_info.span);
 }
 
 pub(crate) fn codegen_panic_inner<'tcx>(
diff --git a/compiler/rustc_codegen_cranelift/src/bin/cg_clif.rs b/compiler/rustc_codegen_cranelift/src/bin/cg_clif.rs
deleted file mode 100644
index 5984ec8..0000000
--- a/compiler/rustc_codegen_cranelift/src/bin/cg_clif.rs
+++ /dev/null
@@ -1,94 +0,0 @@
-#![feature(rustc_private)]
-#![warn(rust_2018_idioms)]
-#![warn(unused_lifetimes)]
-#![warn(unreachable_pub)]
-
-extern crate rustc_data_structures;
-extern crate rustc_driver;
-extern crate rustc_interface;
-extern crate rustc_session;
-extern crate rustc_target;
-
-use std::panic;
-
-use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry};
-use rustc_interface::interface;
-use rustc_session::config::{ErrorOutputType, TrimmedDefPaths};
-use rustc_session::early_error;
-use rustc_target::spec::PanicStrategy;
-
-// FIXME use std::lazy::SyncLazy once it stabilizes
-use once_cell::sync::Lazy;
-
-const BUG_REPORT_URL: &str = "https://github.com/bjorn3/rustc_codegen_cranelift/issues/new";
-
-static DEFAULT_HOOK: Lazy<Box<dyn Fn(&panic::PanicInfo<'_>) + Sync + Send + 'static>> =
-    Lazy::new(|| {
-        let hook = panic::take_hook();
-        panic::set_hook(Box::new(|info| {
-            // Invoke the default handler, which prints the actual panic message and optionally a backtrace
-            (*DEFAULT_HOOK)(info);
-
-            // Separate the output with an empty line
-            eprintln!();
-
-            // Print the ICE message
-            rustc_driver::report_ice(info, BUG_REPORT_URL);
-        }));
-        hook
-    });
-
-#[derive(Default)]
-pub struct CraneliftPassesCallbacks {
-    time_passes: bool,
-}
-
-impl rustc_driver::Callbacks for CraneliftPassesCallbacks {
-    fn config(&mut self, config: &mut interface::Config) {
-        // If a --prints=... option has been given, we don't print the "total"
-        // time because it will mess up the --prints output. See #64339.
-        self.time_passes = config.opts.prints.is_empty()
-            && (config.opts.debugging_opts.time_passes || config.opts.debugging_opts.time);
-
-        config.opts.cg.panic = Some(PanicStrategy::Abort);
-        config.opts.debugging_opts.panic_abort_tests = true;
-        config.opts.maybe_sysroot = Some(config.opts.maybe_sysroot.clone().unwrap_or_else(|| {
-            std::env::current_exe().unwrap().parent().unwrap().parent().unwrap().to_owned()
-        }));
-
-        config.opts.trimmed_def_paths = TrimmedDefPaths::GoodPath;
-    }
-}
-
-fn main() {
-    let start_time = std::time::Instant::now();
-    let start_rss = get_resident_set_size();
-    rustc_driver::init_rustc_env_logger();
-    let mut callbacks = CraneliftPassesCallbacks::default();
-    Lazy::force(&DEFAULT_HOOK); // Install ice hook
-    let exit_code = rustc_driver::catch_with_exit_code(|| {
-        let args = std::env::args_os()
-            .enumerate()
-            .map(|(i, arg)| {
-                arg.into_string().unwrap_or_else(|arg| {
-                    early_error(
-                        ErrorOutputType::default(),
-                        &format!("Argument {} is not valid Unicode: {:?}", i, arg),
-                    )
-                })
-            })
-            .collect::<Vec<_>>();
-        let mut run_compiler = rustc_driver::RunCompiler::new(&args, &mut callbacks);
-        run_compiler.set_make_codegen_backend(Some(Box::new(move |_| {
-            Box::new(rustc_codegen_cranelift::CraneliftCodegenBackend { config: None })
-        })));
-        run_compiler.run()
-    });
-
-    if callbacks.time_passes {
-        let end_rss = get_resident_set_size();
-        print_time_passes_entry("total", start_time.elapsed(), start_rss, end_rss);
-    }
-
-    std::process::exit(exit_code)
-}
diff --git a/compiler/rustc_codegen_cranelift/src/bin/cg_clif_build_sysroot.rs b/compiler/rustc_codegen_cranelift/src/bin/cg_clif_build_sysroot.rs
deleted file mode 100644
index bde4d71..0000000
--- a/compiler/rustc_codegen_cranelift/src/bin/cg_clif_build_sysroot.rs
+++ /dev/null
@@ -1,93 +0,0 @@
-//! The only difference between this and cg_clif.rs is that this binary defaults to using cg_llvm
-//! instead of cg_clif and requires `--clif` to use cg_clif and that this binary doesn't have JIT
-//! support.
-//! This is necessary as with Cargo `RUSTC` applies to both target crates and host crates. The host
-//! crates must be built with cg_llvm as we are currently building a sysroot for cg_clif.
-//! `RUSTFLAGS` however is only applied to target crates, so `--clif` would only be passed to the
-//! target crates.
-
-#![feature(rustc_private)]
-#![warn(rust_2018_idioms)]
-#![warn(unused_lifetimes)]
-#![warn(unreachable_pub)]
-
-extern crate rustc_driver;
-extern crate rustc_interface;
-extern crate rustc_session;
-extern crate rustc_target;
-
-use std::path::PathBuf;
-
-use rustc_interface::interface;
-use rustc_session::config::ErrorOutputType;
-use rustc_session::early_error;
-use rustc_target::spec::PanicStrategy;
-
-fn find_sysroot() -> String {
-    // Taken from https://github.com/Manishearth/rust-clippy/pull/911.
-    let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME"));
-    let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN"));
-    match (home, toolchain) {
-        (Some(home), Some(toolchain)) => format!("{}/toolchains/{}", home, toolchain),
-        _ => option_env!("RUST_SYSROOT")
-            .expect("need to specify RUST_SYSROOT env var or use rustup or multirust")
-            .to_owned(),
-    }
-}
-
-pub struct CraneliftPassesCallbacks {
-    use_clif: bool,
-}
-
-impl rustc_driver::Callbacks for CraneliftPassesCallbacks {
-    fn config(&mut self, config: &mut interface::Config) {
-        if !self.use_clif {
-            config.opts.maybe_sysroot = Some(PathBuf::from(find_sysroot()));
-            return;
-        }
-
-        config.opts.cg.panic = Some(PanicStrategy::Abort);
-        config.opts.debugging_opts.panic_abort_tests = true;
-        config.opts.maybe_sysroot =
-            Some(std::env::current_exe().unwrap().parent().unwrap().parent().unwrap().to_owned());
-    }
-}
-
-fn main() {
-    rustc_driver::init_rustc_env_logger();
-    rustc_driver::install_ice_hook();
-    let exit_code = rustc_driver::catch_with_exit_code(|| {
-        let mut use_clif = false;
-
-        let args = std::env::args_os()
-            .enumerate()
-            .map(|(i, arg)| {
-                arg.into_string().unwrap_or_else(|arg| {
-                    early_error(
-                        ErrorOutputType::default(),
-                        &format!("Argument {} is not valid Unicode: {:?}", i, arg),
-                    )
-                })
-            })
-            .filter(|arg| {
-                if arg == "--clif" {
-                    use_clif = true;
-                    false
-                } else {
-                    true
-                }
-            })
-            .collect::<Vec<_>>();
-
-        let mut callbacks = CraneliftPassesCallbacks { use_clif };
-
-        let mut run_compiler = rustc_driver::RunCompiler::new(&args, &mut callbacks);
-        if use_clif {
-            run_compiler.set_make_codegen_backend(Some(Box::new(move |_| {
-                Box::new(rustc_codegen_cranelift::CraneliftCodegenBackend { config: None })
-            })));
-        }
-        run_compiler.run()
-    });
-    std::process::exit(exit_code)
-}
diff --git a/compiler/rustc_codegen_cranelift/src/common.rs b/compiler/rustc_codegen_cranelift/src/common.rs
index ffa629c..f9dc1b5 100644
--- a/compiler/rustc_codegen_cranelift/src/common.rs
+++ b/compiler/rustc_codegen_cranelift/src/common.rs
@@ -340,22 +340,46 @@
         self.bcx.set_srcloc(SourceLoc::new(index as u32));
     }
 
-    pub(crate) fn get_caller_location(&mut self, span: Span) -> CValue<'tcx> {
-        if let Some(loc) = self.caller_location {
-            // `#[track_caller]` is used; return caller location instead of current location.
-            return loc;
+    // Note: must be kept in sync with get_caller_location from cg_ssa
+    pub(crate) fn get_caller_location(&mut self, mut source_info: mir::SourceInfo) -> CValue<'tcx> {
+        let span_to_caller_location = |fx: &mut FunctionCx<'_, '_, 'tcx>, span: Span| {
+            let topmost = span.ctxt().outer_expn().expansion_cause().unwrap_or(span);
+            let caller = fx.tcx.sess.source_map().lookup_char_pos(topmost.lo());
+            let const_loc = fx.tcx.const_caller_location((
+                rustc_span::symbol::Symbol::intern(
+                    &caller.file.name.prefer_remapped().to_string_lossy(),
+                ),
+                caller.line as u32,
+                caller.col_display as u32 + 1,
+            ));
+            crate::constant::codegen_const_value(fx, const_loc, fx.tcx.caller_location_ty())
+        };
+
+        // Walk up the `SourceScope`s, in case some of them are from MIR inlining.
+        // If so, the starting `source_info.span` is in the innermost inlined
+        // function, and will be replaced with outer callsite spans as long
+        // as the inlined functions were `#[track_caller]`.
+        loop {
+            let scope_data = &self.mir.source_scopes[source_info.scope];
+
+            if let Some((callee, callsite_span)) = scope_data.inlined {
+                // Stop inside the most nested non-`#[track_caller]` function,
+                // before ever reaching its caller (which is irrelevant).
+                if !callee.def.requires_caller_location(self.tcx) {
+                    return span_to_caller_location(self, source_info.span);
+                }
+                source_info.span = callsite_span;
+            }
+
+            // Skip past all of the parents with `inlined: None`.
+            match scope_data.inlined_parent_scope {
+                Some(parent) => source_info.scope = parent,
+                None => break,
+            }
         }
 
-        let topmost = span.ctxt().outer_expn().expansion_cause().unwrap_or(span);
-        let caller = self.tcx.sess.source_map().lookup_char_pos(topmost.lo());
-        let const_loc = self.tcx.const_caller_location((
-            rustc_span::symbol::Symbol::intern(
-                &caller.file.name.prefer_remapped().to_string_lossy(),
-            ),
-            caller.line as u32,
-            caller.col_display as u32 + 1,
-        ));
-        crate::constant::codegen_const_value(self, const_loc, self.tcx.caller_location_ty())
+        // No inlined `SourceScope`s, or all of them were `#[track_caller]`.
+        self.caller_location.unwrap_or_else(|| span_to_caller_location(self, source_info.span))
     }
 
     pub(crate) fn anonymous_str(&mut self, msg: &str) -> Value {
diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs
index 57074f0..ef72e6e 100644
--- a/compiler/rustc_codegen_cranelift/src/constant.rs
+++ b/compiler/rustc_codegen_cranelift/src/constant.rs
@@ -45,7 +45,7 @@
             ConstantKind::Ty(ct) => ct,
             ConstantKind::Val(..) => continue,
         };
-        match const_.val() {
+        match const_.kind() {
             ConstKind::Value(_) => {}
             ConstKind::Unevaluated(unevaluated) => {
                 if let Err(err) =
@@ -126,8 +126,8 @@
         ConstantKind::Ty(ct) => ct,
         ConstantKind::Val(val, ty) => return codegen_const_value(fx, val, ty),
     };
-    let const_val = match const_.val() {
-        ConstKind::Value(const_val) => const_val,
+    let const_val = match const_.kind() {
+        ConstKind::Value(valtree) => fx.tcx.valtree_to_const_val((const_.ty(), valtree)),
         ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted })
             if fx.tcx.is_static(def.did) =>
         {
@@ -468,9 +468,10 @@
 ) -> Option<ConstValue<'tcx>> {
     match operand {
         Operand::Constant(const_) => match const_.literal {
-            ConstantKind::Ty(const_) => {
-                fx.monomorphize(const_).eval(fx.tcx, ParamEnv::reveal_all()).val().try_to_value()
-            }
+            ConstantKind::Ty(const_) => fx
+                .monomorphize(const_)
+                .eval_for_mir(fx.tcx, ParamEnv::reveal_all())
+                .try_to_value(fx.tcx),
             ConstantKind::Val(val, _) => Some(val),
         },
         // FIXME(rust-lang/rust#85105): Casts like `IMM8 as u32` result in the const being stored
@@ -542,8 +543,8 @@
                     | TerminatorKind::FalseEdge { .. }
                     | TerminatorKind::FalseUnwind { .. } => unreachable!(),
                     TerminatorKind::InlineAsm { .. } => return None,
-                    TerminatorKind::Call { destination: Some((call_place, _)), .. }
-                        if call_place == place =>
+                    TerminatorKind::Call { destination, target: Some(_), .. }
+                        if destination == place =>
                     {
                         return None;
                     }
diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs
index 5e1e1c8..05457ce 100644
--- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs
+++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs
@@ -66,11 +66,7 @@
     let work_product = if backend_config.disable_incr_cache {
         None
     } else {
-        rustc_incremental::copy_cgu_workproduct_to_incr_comp_cache_dir(
-            tcx.sess,
-            &name,
-            &Some(tmp_file.clone()),
-        )
+        rustc_incremental::copy_cgu_workproduct_to_incr_comp_cache_dir(tcx.sess, &name, &tmp_file)
     };
 
     ModuleCodegenResult(
@@ -84,21 +80,16 @@
     cgu: &CodegenUnit<'_>,
     work_products: &mut FxHashMap<WorkProductId, WorkProduct>,
 ) -> CompiledModule {
-    let mut object = None;
-    let work_product = cgu.work_product(tcx);
-    if let Some(saved_file) = &work_product.saved_file {
-        let obj_out =
-            tcx.output_filenames(()).temp_path(OutputType::Object, Some(cgu.name().as_str()));
-        object = Some(obj_out.clone());
-        let source_file = rustc_incremental::in_incr_comp_dir_sess(&tcx.sess, &saved_file);
-        if let Err(err) = rustc_fs_util::link_or_copy(&source_file, &obj_out) {
-            tcx.sess.err(&format!(
-                "unable to copy {} to {}: {}",
-                source_file.display(),
-                obj_out.display(),
-                err
-            ));
-        }
+    let work_product = cgu.previous_work_product(tcx);
+    let obj_out = tcx.output_filenames(()).temp_path(OutputType::Object, Some(cgu.name().as_str()));
+    let source_file = rustc_incremental::in_incr_comp_dir_sess(&tcx.sess, &work_product.saved_file);
+    if let Err(err) = rustc_fs_util::link_or_copy(&source_file, &obj_out) {
+        tcx.sess.err(&format!(
+            "unable to copy {} to {}: {}",
+            source_file.display(),
+            obj_out.display(),
+            err
+        ));
     }
 
     work_products.insert(cgu.work_product_id(), work_product);
@@ -106,7 +97,7 @@
     CompiledModule {
         name: cgu.name().to_string(),
         kind: ModuleKind::Regular,
-        object,
+        object: Some(obj_out),
         dwarf_object: None,
         bytecode: None,
     }
diff --git a/compiler/rustc_codegen_cranelift/src/driver/jit.rs b/compiler/rustc_codegen_cranelift/src/driver/jit.rs
index 7f15bc7..a56a910 100644
--- a/compiler/rustc_codegen_cranelift/src/driver/jit.rs
+++ b/compiler/rustc_codegen_cranelift/src/driver/jit.rs
@@ -13,7 +13,7 @@
 
 use cranelift_jit::{JITBuilder, JITModule};
 
-// FIXME use std::lazy::SyncOnceCell once it stabilizes
+// FIXME use std::sync::OnceLock once it stabilizes
 use once_cell::sync::OnceCell;
 
 use crate::{prelude::*, BackendConfig};
@@ -74,6 +74,7 @@
     jit_builder.hotswap(hotswap);
     crate::compiler_builtins::register_functions_for_jit(&mut jit_builder);
     jit_builder.symbols(imported_symbols);
+    jit_builder.symbol("__clif_jit_fn", clif_jit_fn as *const u8);
     let mut jit_module = JITModule::new(jit_builder);
 
     let mut cx = crate::CodegenCx::new(
@@ -210,8 +211,7 @@
     }
 }
 
-#[no_mangle]
-extern "C" fn __clif_jit_fn(
+extern "C" fn clif_jit_fn(
     instance_ptr: *const Instance<'static>,
     trampoline_ptr: *const u8,
 ) -> *const u8 {
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs
index 0e4f7ee..77ac465 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs
@@ -10,10 +10,9 @@
     intrinsic: &str,
     _substs: SubstsRef<'tcx>,
     args: &[mir::Operand<'tcx>],
-    destination: Option<(CPlace<'tcx>, BasicBlock)>,
+    ret: CPlace<'tcx>,
+    target: Option<BasicBlock>,
 ) {
-    let ret = destination.unwrap().0;
-
     intrinsic_match! {
         fx, intrinsic, args,
         _ => {
@@ -126,7 +125,7 @@
         };
     }
 
-    let dest = destination.expect("all llvm intrinsics used by stdlib should return").1;
+    let dest = target.expect("all llvm intrinsics used by stdlib should return");
     let ret_block = fx.get_block(dest);
     fx.bcx.ins().jump(ret_block, &[]);
 }
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
index f7a8337..6937e65 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
@@ -58,6 +58,7 @@
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::subst::SubstsRef;
 use rustc_span::symbol::{kw, sym, Symbol};
+use rustc_target::abi::InitKind;
 
 use crate::prelude::*;
 use cranelift_codegen::ir::AtomicRmwOp;
@@ -217,35 +218,42 @@
     fx: &mut FunctionCx<'_, '_, 'tcx>,
     instance: Instance<'tcx>,
     args: &[mir::Operand<'tcx>],
-    destination: Option<(CPlace<'tcx>, BasicBlock)>,
-    span: Span,
+    destination: CPlace<'tcx>,
+    target: Option<BasicBlock>,
+    source_info: mir::SourceInfo,
 ) {
     let intrinsic = fx.tcx.item_name(instance.def_id());
     let substs = instance.substs;
 
-    let ret = match destination {
-        Some((place, _)) => place,
-        None => {
-            // Insert non returning intrinsics here
-            match intrinsic {
-                sym::abort => {
-                    fx.bcx.ins().trap(TrapCode::User(0));
-                }
-                sym::transmute => {
-                    crate::base::codegen_panic(fx, "Transmuting to uninhabited type.", span);
-                }
-                _ => unimplemented!("unsupported instrinsic {}", intrinsic),
+    let target = if let Some(target) = target {
+        target
+    } else {
+        // Insert non returning intrinsics here
+        match intrinsic {
+            sym::abort => {
+                fx.bcx.ins().trap(TrapCode::User(0));
             }
-            return;
+            sym::transmute => {
+                crate::base::codegen_panic(fx, "Transmuting to uninhabited type.", source_info);
+            }
+            _ => unimplemented!("unsupported instrinsic {}", intrinsic),
         }
+        return;
     };
 
     if intrinsic.as_str().starts_with("simd_") {
-        self::simd::codegen_simd_intrinsic_call(fx, intrinsic, substs, args, ret, span);
-        let ret_block = fx.get_block(destination.expect("SIMD intrinsics don't diverge").1);
+        self::simd::codegen_simd_intrinsic_call(
+            fx,
+            intrinsic,
+            substs,
+            args,
+            destination,
+            source_info.span,
+        );
+        let ret_block = fx.get_block(target);
         fx.bcx.ins().jump(ret_block, &[]);
-    } else if codegen_float_intrinsic_call(fx, intrinsic, args, ret) {
-        let ret_block = fx.get_block(destination.expect("Float intrinsics don't diverge").1);
+    } else if codegen_float_intrinsic_call(fx, intrinsic, args, destination) {
+        let ret_block = fx.get_block(target);
         fx.bcx.ins().jump(ret_block, &[]);
     } else {
         codegen_regular_intrinsic_call(
@@ -254,9 +262,9 @@
             intrinsic,
             substs,
             args,
-            ret,
-            span,
             destination,
+            Some(target),
+            source_info,
         );
     }
 }
@@ -339,15 +347,15 @@
     substs: SubstsRef<'tcx>,
     args: &[mir::Operand<'tcx>],
     ret: CPlace<'tcx>,
-    span: Span,
-    destination: Option<(CPlace<'tcx>, BasicBlock)>,
+    destination: Option<BasicBlock>,
+    source_info: mir::SourceInfo,
 ) {
     let usize_layout = fx.layout_of(fx.tcx.types.usize);
 
     intrinsic_match! {
         fx, intrinsic, args,
         _ => {
-            fx.tcx.sess.span_fatal(span, &format!("unsupported intrinsic {}", intrinsic));
+            fx.tcx.sess.span_fatal(source_info.span, &format!("unsupported intrinsic {}", intrinsic));
         };
 
         assume, (c _a) {};
@@ -658,29 +666,39 @@
                     crate::base::codegen_panic(
                         fx,
                         &format!("attempted to instantiate uninhabited type `{}`", layout.ty),
-                        span,
+                        source_info,
                     )
                 });
                 return;
             }
 
-            if intrinsic == sym::assert_zero_valid && !layout.might_permit_raw_init(fx, /*zero:*/ true) {
+            if intrinsic == sym::assert_zero_valid
+                && !layout.might_permit_raw_init(
+                    fx,
+                    InitKind::Zero,
+                    fx.tcx.sess.opts.debugging_opts.strict_init_checks) {
+
                 with_no_trimmed_paths!({
                     crate::base::codegen_panic(
                         fx,
                         &format!("attempted to zero-initialize type `{}`, which is invalid", layout.ty),
-                        span,
+                        source_info,
                     );
                 });
                 return;
             }
 
-            if intrinsic == sym::assert_uninit_valid && !layout.might_permit_raw_init(fx, /*zero:*/ false) {
+            if intrinsic == sym::assert_uninit_valid
+                && !layout.might_permit_raw_init(
+                    fx,
+                    InitKind::Uninit,
+                    fx.tcx.sess.opts.debugging_opts.strict_init_checks) {
+
                 with_no_trimmed_paths!({
                     crate::base::codegen_panic(
                         fx,
                         &format!("attempted to leave type `{}` uninitialized, which is invalid", layout.ty),
-                        span,
+                        source_info,
                     )
                 });
                 return;
@@ -715,19 +733,19 @@
 
         ptr_offset_from | ptr_offset_from_unsigned, (v ptr, v base) {
             let ty = substs.type_at(0);
-            let isize_layout = fx.layout_of(fx.tcx.types.isize);
 
             let pointee_size: u64 = fx.layout_of(ty).size.bytes();
             let diff_bytes = fx.bcx.ins().isub(ptr, base);
             // FIXME this can be an exact division.
-            let diff = if intrinsic == sym::ptr_offset_from_unsigned {
+            let val = if intrinsic == sym::ptr_offset_from_unsigned {
+                let usize_layout = fx.layout_of(fx.tcx.types.usize);
                 // Because diff_bytes ULE isize::MAX, this would be fine as signed,
                 // but unsigned is slightly easier to codegen, so might as well.
-                fx.bcx.ins().udiv_imm(diff_bytes, pointee_size as i64)
+                CValue::by_val(fx.bcx.ins().udiv_imm(diff_bytes, pointee_size as i64), usize_layout)
             } else {
-                fx.bcx.ins().sdiv_imm(diff_bytes, pointee_size as i64)
+                let isize_layout = fx.layout_of(fx.tcx.types.isize);
+                CValue::by_val(fx.bcx.ins().sdiv_imm(diff_bytes, pointee_size as i64), isize_layout)
             };
-            let val = CValue::by_val(diff, isize_layout);
             ret.write_cvalue(fx, val);
         };
 
@@ -742,7 +760,7 @@
         };
 
         caller_location, () {
-            let caller_location = fx.get_caller_location(span);
+            let caller_location = fx.get_caller_location(source_info);
             ret.write_cvalue(fx, caller_location);
         };
 
@@ -761,16 +779,16 @@
                     if fx.tcx.is_compiler_builtins(LOCAL_CRATE) {
                         // special case for compiler-builtins to avoid having to patch it
                         crate::trap::trap_unimplemented(fx, "128bit atomics not yet supported");
-                        let ret_block = fx.get_block(destination.unwrap().1);
+                        let ret_block = fx.get_block(destination.unwrap());
                         fx.bcx.ins().jump(ret_block, &[]);
                         return;
                     } else {
-                        fx.tcx.sess.span_fatal(span, "128bit atomics not yet supported");
+                        fx.tcx.sess.span_fatal(source_info.span, "128bit atomics not yet supported");
                     }
                 }
                 ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
                 _ => {
-                    report_atomic_type_validation_error(fx, intrinsic, span, ty);
+                    report_atomic_type_validation_error(fx, intrinsic, source_info.span, ty);
                     return;
                 }
             }
@@ -789,16 +807,16 @@
                     if fx.tcx.is_compiler_builtins(LOCAL_CRATE) {
                         // special case for compiler-builtins to avoid having to patch it
                         crate::trap::trap_unimplemented(fx, "128bit atomics not yet supported");
-                        let ret_block = fx.get_block(destination.unwrap().1);
+                        let ret_block = fx.get_block(destination.unwrap());
                         fx.bcx.ins().jump(ret_block, &[]);
                         return;
                     } else {
-                        fx.tcx.sess.span_fatal(span, "128bit atomics not yet supported");
+                        fx.tcx.sess.span_fatal(source_info.span, "128bit atomics not yet supported");
                     }
                 }
                 ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
                 _ => {
-                    report_atomic_type_validation_error(fx, intrinsic, span, ty);
+                    report_atomic_type_validation_error(fx, intrinsic, source_info.span, ty);
                     return;
                 }
             }
@@ -812,7 +830,7 @@
             match layout.ty.kind() {
                 ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
                 _ => {
-                    report_atomic_type_validation_error(fx, intrinsic, span, layout.ty);
+                    report_atomic_type_validation_error(fx, intrinsic, source_info.span, layout.ty);
                     return;
                 }
             }
@@ -830,7 +848,7 @@
             match layout.ty.kind() {
                 ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
                 _ => {
-                    report_atomic_type_validation_error(fx, intrinsic, span, layout.ty);
+                    report_atomic_type_validation_error(fx, intrinsic, source_info.span, layout.ty);
                     return;
                 }
             }
@@ -850,7 +868,7 @@
             match layout.ty.kind() {
                 ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
                 _ => {
-                    report_atomic_type_validation_error(fx, intrinsic, span, layout.ty);
+                    report_atomic_type_validation_error(fx, intrinsic, source_info.span, layout.ty);
                     return;
                 }
             }
@@ -868,7 +886,7 @@
             match layout.ty.kind() {
                 ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
                 _ => {
-                    report_atomic_type_validation_error(fx, intrinsic, span, layout.ty);
+                    report_atomic_type_validation_error(fx, intrinsic, source_info.span, layout.ty);
                     return;
                 }
             }
@@ -886,7 +904,7 @@
             match layout.ty.kind() {
                 ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
                 _ => {
-                    report_atomic_type_validation_error(fx, intrinsic, span, layout.ty);
+                    report_atomic_type_validation_error(fx, intrinsic, source_info.span, layout.ty);
                     return;
                 }
             }
@@ -904,7 +922,7 @@
             match layout.ty.kind() {
                 ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
                 _ => {
-                    report_atomic_type_validation_error(fx, intrinsic, span, layout.ty);
+                    report_atomic_type_validation_error(fx, intrinsic, source_info.span, layout.ty);
                     return;
                 }
             }
@@ -922,7 +940,7 @@
             match layout.ty.kind() {
                 ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
                 _ => {
-                    report_atomic_type_validation_error(fx, intrinsic, span, layout.ty);
+                    report_atomic_type_validation_error(fx, intrinsic, source_info.span, layout.ty);
                     return;
                 }
             }
@@ -940,7 +958,7 @@
             match layout.ty.kind() {
                 ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
                 _ => {
-                    report_atomic_type_validation_error(fx, intrinsic, span, layout.ty);
+                    report_atomic_type_validation_error(fx, intrinsic, source_info.span, layout.ty);
                     return;
                 }
             }
@@ -958,7 +976,7 @@
             match layout.ty.kind() {
                 ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
                 _ => {
-                    report_atomic_type_validation_error(fx, intrinsic, span, layout.ty);
+                    report_atomic_type_validation_error(fx, intrinsic, source_info.span, layout.ty);
                     return;
                 }
             }
@@ -976,7 +994,7 @@
             match layout.ty.kind() {
                 ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
                 _ => {
-                    report_atomic_type_validation_error(fx, intrinsic, span, layout.ty);
+                    report_atomic_type_validation_error(fx, intrinsic, source_info.span, layout.ty);
                     return;
                 }
             }
@@ -994,7 +1012,7 @@
             match layout.ty.kind() {
                 ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
                 _ => {
-                    report_atomic_type_validation_error(fx, intrinsic, span, layout.ty);
+                    report_atomic_type_validation_error(fx, intrinsic, source_info.span, layout.ty);
                     return;
                 }
             }
@@ -1012,7 +1030,7 @@
             match layout.ty.kind() {
                 ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
                 _ => {
-                    report_atomic_type_validation_error(fx, intrinsic, span, layout.ty);
+                    report_atomic_type_validation_error(fx, intrinsic, source_info.span, layout.ty);
                     return;
                 }
             }
@@ -1130,6 +1148,6 @@
         };
     }
 
-    let ret_block = fx.get_block(destination.unwrap().1);
+    let ret_block = fx.get_block(destination.unwrap());
     fx.bcx.ins().jump(ret_block, &[]);
 }
diff --git a/compiler/rustc_codegen_cranelift/src/value_and_place.rs b/compiler/rustc_codegen_cranelift/src/value_and_place.rs
index 8f80b02..a68225d 100644
--- a/compiler/rustc_codegen_cranelift/src/value_and_place.rs
+++ b/compiler/rustc_codegen_cranelift/src/value_and_place.rs
@@ -828,6 +828,7 @@
                 }
             }
         }
+        (ty::Array(a, _), ty::Array(b, _)) => assert_assignable(fx, *a, *b),
         _ => {
             assert_eq!(
                 from_ty, to_ty,
diff --git a/compiler/rustc_codegen_gcc/.github/workflows/ci.yml b/compiler/rustc_codegen_gcc/.github/workflows/ci.yml
index 337837c..8ebdabe 100644
--- a/compiler/rustc_codegen_gcc/.github/workflows/ci.yml
+++ b/compiler/rustc_codegen_gcc/.github/workflows/ci.yml
@@ -11,7 +11,7 @@
     strategy:
       fail-fast: false
       matrix:
-        libgccjit_version: ["libgccjit.so", "libgccjit_without_int128.so"]
+        libgccjit_version: ["libgccjit.so", "libgccjit_without_int128.so", "libgccjit12.so"]
 
     steps:
     - uses: actions/checkout@v2
@@ -78,12 +78,21 @@
         key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('rust-toolchain') }}
 
     - name: Build
+      if: matrix.libgccjit_version != 'libgccjit12.so'
       run: |
         ./prepare_build.sh
         ./build.sh
         cargo test
         ./clean_all.sh
 
+    - name: Build
+      if: matrix.libgccjit_version == 'libgccjit12.so'
+      run: |
+        ./prepare_build.sh
+        ./build.sh --no-default-features
+        cargo test --no-default-features
+        ./clean_all.sh
+
     - name: Prepare dependencies
       run: |
         git config --global user.email "[email protected]"
@@ -98,6 +107,7 @@
         args: --release
 
     - name: Test
+      if: matrix.libgccjit_version != 'libgccjit12.so'
       run: |
         # Enable backtraces for easier debugging
         export RUST_BACKTRACE=1
@@ -107,3 +117,15 @@
         export RUN_RUNS=2
 
         ./test.sh --release
+
+    - name: Test
+      if: matrix.libgccjit_version == 'libgccjit12.so'
+      run: |
+        # Enable backtraces for easier debugging
+        export RUST_BACKTRACE=1
+
+        # Reduce amount of benchmark runs as they are slow
+        export COMPILE_RUNS=2
+        export RUN_RUNS=2
+
+        ./test.sh --release --no-default-features
diff --git a/compiler/rustc_codegen_gcc/.rustfmt.toml b/compiler/rustc_codegen_gcc/.rustfmt.toml
new file mode 100644
index 0000000..c7ad93b
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/.rustfmt.toml
@@ -0,0 +1 @@
+disable_all_formatting = true
diff --git a/compiler/rustc_codegen_gcc/Cargo.lock b/compiler/rustc_codegen_gcc/Cargo.lock
index a1d9f2f..6df2102 100644
--- a/compiler/rustc_codegen_gcc/Cargo.lock
+++ b/compiler/rustc_codegen_gcc/Cargo.lock
@@ -41,7 +41,7 @@
 [[package]]
 name = "gccjit"
 version = "1.0.0"
-source = "git+https://github.com/antoyo/gccjit.rs#bdecdecfb8a02ec861a39a350f990faa33bd31c3"
+source = "git+https://github.com/antoyo/gccjit.rs#bdb86fb5092895ff5589726b33250010c64d93f6"
 dependencies = [
  "gccjit_sys",
 ]
@@ -49,7 +49,7 @@
 [[package]]
 name = "gccjit_sys"
 version = "0.0.1"
-source = "git+https://github.com/antoyo/gccjit.rs#bdecdecfb8a02ec861a39a350f990faa33bd31c3"
+source = "git+https://github.com/antoyo/gccjit.rs#bdb86fb5092895ff5589726b33250010c64d93f6"
 dependencies = [
  "libc 0.1.12",
 ]
diff --git a/compiler/rustc_codegen_gcc/Cargo.toml b/compiler/rustc_codegen_gcc/Cargo.toml
index 21f0bfb..211d19a 100644
--- a/compiler/rustc_codegen_gcc/Cargo.toml
+++ b/compiler/rustc_codegen_gcc/Cargo.toml
@@ -9,9 +9,17 @@
 crate-type = ["dylib"]
 
 [[test]]
-name = "lang_tests"
-path = "tests/lib.rs"
+name = "lang_tests_debug"
+path = "tests/lang_tests_debug.rs"
 harness = false
+[[test]]
+name = "lang_tests_release"
+path = "tests/lang_tests_release.rs"
+harness = false
+
+[features]
+default = ["master"]
+master = ["gccjit/master"]
 
 [dependencies]
 gccjit = { git = "https://github.com/antoyo/gccjit.rs" }
diff --git a/compiler/rustc_codegen_gcc/build.sh b/compiler/rustc_codegen_gcc/build.sh
index 230ab7b..ba0d0d0 100755
--- a/compiler/rustc_codegen_gcc/build.sh
+++ b/compiler/rustc_codegen_gcc/build.sh
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
 
 #set -x
 set -e
@@ -6,6 +6,8 @@
 codegen_channel=debug
 sysroot_channel=debug
 
+flags=
+
 while [[ $# -gt 0 ]]; do
     case $1 in
         --release)
@@ -16,6 +18,15 @@
             sysroot_channel=release
             shift
             ;;
+        --no-default-features)
+            flags="$flags --no-default-features"
+            shift
+            ;;
+        --features)
+            shift
+            flags="$flags --features $1"
+            shift
+            ;;
         *)
             echo "Unknown option $1"
             exit 1
@@ -33,21 +44,13 @@
 export LD_LIBRARY_PATH="$GCC_PATH"
 export LIBRARY_PATH="$GCC_PATH"
 
-features=
-
-if [[ "$1" == "--features" ]]; then
-    shift
-    features="--features $1"
-    shift
-fi
-
 if [[ "$codegen_channel" == "release" ]]; then
     export CHANNEL='release'
-    CARGO_INCREMENTAL=1 cargo rustc --release $features
+    CARGO_INCREMENTAL=1 cargo rustc --release $flags
 else
     echo $LD_LIBRARY_PATH
     export CHANNEL='debug'
-    cargo rustc $features
+    cargo rustc $flags
 fi
 
 source config.sh
diff --git a/compiler/rustc_codegen_gcc/build_sysroot/build_sysroot.sh b/compiler/rustc_codegen_gcc/build_sysroot/build_sysroot.sh
index a965ca9..f293192 100755
--- a/compiler/rustc_codegen_gcc/build_sysroot/build_sysroot.sh
+++ b/compiler/rustc_codegen_gcc/build_sysroot/build_sysroot.sh
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
 
 # Requires the CHANNEL env var to be set to `debug` or `release.`
 
diff --git a/compiler/rustc_codegen_gcc/build_sysroot/prepare_sysroot_src.sh b/compiler/rustc_codegen_gcc/build_sysroot/prepare_sysroot_src.sh
index 071e7ed..56768bb 100755
--- a/compiler/rustc_codegen_gcc/build_sysroot/prepare_sysroot_src.sh
+++ b/compiler/rustc_codegen_gcc/build_sysroot/prepare_sysroot_src.sh
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
 set -e
 cd $(dirname "$0")
 
diff --git a/compiler/rustc_codegen_gcc/cargo.sh b/compiler/rustc_codegen_gcc/cargo.sh
index 332f365..16e49b2 100755
--- a/compiler/rustc_codegen_gcc/cargo.sh
+++ b/compiler/rustc_codegen_gcc/cargo.sh
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
 
 if [ -z $CHANNEL ]; then
 export CHANNEL='debug'
@@ -20,4 +20,4 @@
 cmd=$1
 shift
 
-RUSTDOCFLAGS="$RUSTFLAGS" cargo +${TOOLCHAIN} $cmd --target $TARGET_TRIPLE $@
+RUSTDOCFLAGS="$RUSTFLAGS" cargo +${TOOLCHAIN} $cmd $@
diff --git a/compiler/rustc_codegen_gcc/clean_all.sh b/compiler/rustc_codegen_gcc/clean_all.sh
index a77d148..782bd3e 100755
--- a/compiler/rustc_codegen_gcc/clean_all.sh
+++ b/compiler/rustc_codegen_gcc/clean_all.sh
@@ -1,5 +1,6 @@
-#!/bin/bash --verbose
+#!/usr/bin/env bash
 set -e
+set -v
 
 rm -rf target/ build_sysroot/{sysroot/,sysroot_src/,target/,Cargo.lock} perf.data{,.old}
 rm -rf regex/ simple-raytracer/
diff --git a/compiler/rustc_codegen_gcc/config.sh b/compiler/rustc_codegen_gcc/config.sh
index a932c1c..b25e215 100644
--- a/compiler/rustc_codegen_gcc/config.sh
+++ b/compiler/rustc_codegen_gcc/config.sh
@@ -2,7 +2,7 @@
 
 export CARGO_INCREMENTAL=0
 
-if [ -f ./gcc_path ]; then 
+if [ -f ./gcc_path ]; then
     export GCC_PATH=$(cat gcc_path)
 else
     echo 'Please put the path to your custom build of libgccjit in the file `gcc_path`, see Readme.md for details'
@@ -38,7 +38,7 @@
    fi
 fi
 
-export RUSTFLAGS="$linker -Cpanic=abort -Csymbol-mangling-version=v0 -Cdebuginfo=2 -Clto=off -Zpanic-abort-tests -Zcodegen-backend=$(pwd)/target/${CHANNEL:-debug}/librustc_codegen_gcc.$dylib_ext --sysroot $(pwd)/build_sysroot/sysroot"
+export RUSTFLAGS="$CG_RUSTFLAGS $linker -Cpanic=abort -Csymbol-mangling-version=v0 -Cdebuginfo=2 -Clto=off -Zpanic-abort-tests -Zcodegen-backend=$(pwd)/target/${CHANNEL:-debug}/librustc_codegen_gcc.$dylib_ext --sysroot $(pwd)/build_sysroot/sysroot"
 
 # FIXME(antoyo): remove once the atomic shim is gone
 if [[ `uname` == 'Darwin' ]]; then
diff --git a/compiler/rustc_codegen_gcc/crate_patches/0002-rand-Disable-failing-test.patch b/compiler/rustc_codegen_gcc/crate_patches/0002-rand-Disable-failing-test.patch
new file mode 100644
index 0000000..449ca5f
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/crate_patches/0002-rand-Disable-failing-test.patch
@@ -0,0 +1,32 @@
+From a8fb97120d71252538b6b026695df40d02696bdb Mon Sep 17 00:00:00 2001
+From: bjorn3 <[email protected]>
+Date: Sat, 15 Aug 2020 20:04:38 +0200
+Subject: [PATCH] [rand] Disable failing test
+
+---
+ src/distributions/uniform.rs | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/src/distributions/uniform.rs b/src/distributions/uniform.rs
+index 480b859..c80bb6f 100644
+--- a/src/distributions/uniform.rs
++++ b/src/distributions/uniform.rs
+@@ -1085,7 +1085,7 @@ mod tests {
+             _ => panic!("`UniformDurationMode` was not serialized/deserialized correctly")
+         }
+     }
+-    
++
+     #[test]
+     #[cfg(feature = "serde1")]
+     fn test_uniform_serialization() {
+@@ -1314,6 +1314,7 @@ mod tests {
+         not(target_arch = "wasm32"),
+         not(target_arch = "asmjs")
+     ))]
++    #[ignore] // FIXME
+     fn test_float_assertions() {
+         use super::SampleUniform;
+         use std::panic::catch_unwind;
+-- 
+2.20.1
diff --git a/compiler/rustc_codegen_gcc/example/mini_core.rs b/compiler/rustc_codegen_gcc/example/mini_core.rs
index a843528..ddcbb0d 100644
--- a/compiler/rustc_codegen_gcc/example/mini_core.rs
+++ b/compiler/rustc_codegen_gcc/example/mini_core.rs
@@ -514,7 +514,7 @@
         pub fn copy<T>(src: *const T, dst: *mut T, count: usize);
         pub fn transmute<T, U>(e: T) -> U;
         pub fn ctlz_nonzero<T>(x: T) -> T;
-        pub fn needs_drop<T>() -> bool;
+        pub fn needs_drop<T: ?::Sized>() -> bool;
         pub fn bitreverse<T>(x: T) -> T;
         pub fn bswap<T>(x: T) -> T;
         pub fn write_bytes<T>(dst: *mut T, val: u8, count: usize);
diff --git a/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs b/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs
index 69d5915..14fd9ee 100644
--- a/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs
+++ b/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs
@@ -47,6 +47,11 @@
     inner: NoisyDropInner,
 }
 
+struct NoisyDropUnsized {
+    inner: NoisyDropInner,
+    text: str,
+}
+
 struct NoisyDropInner;
 
 impl Drop for NoisyDrop {
@@ -184,7 +189,9 @@
         assert_eq!(intrinsics::min_align_of_val(&a) as u8, intrinsics::min_align_of::<&str>() as u8);
 
         assert!(!intrinsics::needs_drop::<u8>());
+        assert!(!intrinsics::needs_drop::<[u8]>());
         assert!(intrinsics::needs_drop::<NoisyDrop>());
+        assert!(intrinsics::needs_drop::<NoisyDropUnsized>());
 
         Unique {
             pointer: 0 as *const &str,
diff --git a/compiler/rustc_codegen_gcc/example/std_example.rs b/compiler/rustc_codegen_gcc/example/std_example.rs
index eba0eb8..3106905 100644
--- a/compiler/rustc_codegen_gcc/example/std_example.rs
+++ b/compiler/rustc_codegen_gcc/example/std_example.rs
@@ -93,9 +93,10 @@
 
     println!("{:?}", std::intrinsics::caller_location());
 
-    /*unsafe {
+    #[cfg(feature="master")]
+    unsafe {
         test_simd();
-    }*/
+    }
 
     Box::pin(move |mut _task_context| {
         yield ();
@@ -104,7 +105,8 @@
     println!("End");
 }
 
-/*#[target_feature(enable = "sse2")]
+#[cfg(feature="master")]
+#[target_feature(enable = "sse2")]
 unsafe fn test_simd() {
     let x = _mm_setzero_si128();
     let y = _mm_set1_epi16(7);
@@ -112,7 +114,7 @@
     let cmp_eq = _mm_cmpeq_epi8(y, y);
     let cmp_lt = _mm_cmplt_epi8(y, y);
 
-    /*assert_eq!(std::mem::transmute::<_, [u16; 8]>(or), [7, 7, 7, 7, 7, 7, 7, 7]);
+    assert_eq!(std::mem::transmute::<_, [u16; 8]>(or), [7, 7, 7, 7, 7, 7, 7, 7]);
     assert_eq!(std::mem::transmute::<_, [u16; 8]>(cmp_eq), [0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff]);
     assert_eq!(std::mem::transmute::<_, [u16; 8]>(cmp_lt), [0, 0, 0, 0, 0, 0, 0, 0]);
 
@@ -124,14 +126,15 @@
     test_mm_cvtepi8_epi16();
     test_mm_cvtsi128_si64();
 
-    // FIXME(#666) implement `#[rustc_arg_required_const(..)]` support
-    //test_mm_extract_epi8();
+    test_mm_extract_epi8();
+    test_mm_insert_epi16();
 
     let mask1 = _mm_movemask_epi8(dbg!(_mm_setr_epi8(255u8 as i8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)));
-    assert_eq!(mask1, 1);*/
-}*/
+    assert_eq!(mask1, 1);
+}
 
-/*#[target_feature(enable = "sse2")]
+#[cfg(feature="master")]
+#[target_feature(enable = "sse2")]
 unsafe fn test_mm_slli_si128() {
     #[rustfmt::skip]
     let a = _mm_setr_epi8(
@@ -155,22 +158,10 @@
     );
     let r = _mm_slli_si128(a, 16);
     assert_eq_m128i(r, _mm_set1_epi8(0));
-
-    #[rustfmt::skip]
-    let a = _mm_setr_epi8(
-        1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
-    );
-    let r = _mm_slli_si128(a, -1);
-    assert_eq_m128i(_mm_set1_epi8(0), r);
-
-    #[rustfmt::skip]
-    let a = _mm_setr_epi8(
-        1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
-    );
-    let r = _mm_slli_si128(a, -0x80000000);
-    assert_eq_m128i(r, _mm_set1_epi8(0));
 }
 
+
+#[cfg(feature="master")]
 #[target_feature(enable = "sse2")]
 unsafe fn test_mm_movemask_epi8() {
     #[rustfmt::skip]
@@ -184,6 +175,7 @@
     assert_eq!(r, 0b10100100_00100101);
 }
 
+#[cfg(feature="master")]
 #[target_feature(enable = "avx2")]
 unsafe fn test_mm256_movemask_epi8() {
     let a = _mm256_set1_epi8(-1);
@@ -192,6 +184,7 @@
     assert_eq!(r, e);
 }
 
+#[cfg(feature="master")]
 #[target_feature(enable = "sse2")]
 unsafe fn test_mm_add_epi8() {
     let a = _mm_setr_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);
@@ -207,6 +200,7 @@
     assert_eq_m128i(r, e);
 }
 
+#[cfg(feature="master")]
 #[target_feature(enable = "sse2")]
 unsafe fn test_mm_add_pd() {
     let a = _mm_setr_pd(1.0, 2.0);
@@ -215,12 +209,14 @@
     assert_eq_m128d(r, _mm_setr_pd(6.0, 12.0));
 }
 
+#[cfg(feature="master")]
 fn assert_eq_m128i(x: std::arch::x86_64::__m128i, y: std::arch::x86_64::__m128i) {
     unsafe {
         assert_eq!(std::mem::transmute::<_, [u8; 16]>(x), std::mem::transmute::<_, [u8; 16]>(y));
     }
 }
 
+#[cfg(feature="master")]
 #[target_feature(enable = "sse2")]
 pub unsafe fn assert_eq_m128d(a: __m128d, b: __m128d) {
     if _mm_movemask_pd(_mm_cmpeq_pd(a, b)) != 0b11 {
@@ -228,12 +224,14 @@
     }
 }
 
+#[cfg(feature="master")]
 #[target_feature(enable = "sse2")]
 unsafe fn test_mm_cvtsi128_si64() {
     let r = _mm_cvtsi128_si64(std::mem::transmute::<[i64; 2], _>([5, 0]));
     assert_eq!(r, 5);
 }
 
+#[cfg(feature="master")]
 #[target_feature(enable = "sse4.1")]
 unsafe fn test_mm_cvtepi8_epi16() {
     let a = _mm_set1_epi8(10);
@@ -246,6 +244,7 @@
     assert_eq_m128i(r, e);
 }
 
+#[cfg(feature="master")]
 #[target_feature(enable = "sse4.1")]
 unsafe fn test_mm_extract_epi8() {
     #[rustfmt::skip]
@@ -254,10 +253,19 @@
         8, 9, 10, 11, 12, 13, 14, 15
     );
     let r1 = _mm_extract_epi8(a, 0);
-    let r2 = _mm_extract_epi8(a, 19);
+    let r2 = _mm_extract_epi8(a, 3);
     assert_eq!(r1, 0xFF);
     assert_eq!(r2, 3);
-}*/
+}
+
+#[cfg(all(feature="master", target_arch = "x86_64"))]
+#[target_feature(enable = "sse2")]
+unsafe fn test_mm_insert_epi16() {
+    let a = _mm_setr_epi16(0, 1, 2, 3, 4, 5, 6, 7);
+    let r = _mm_insert_epi16(a, 9, 0);
+    let e = _mm_setr_epi16(9, 1, 2, 3, 4, 5, 6, 7);
+    assert_eq_m128i(r, e);
+}
 
 #[derive(PartialEq)]
 enum LoopState {
diff --git a/compiler/rustc_codegen_gcc/patches/0024-core-Disable-portable-simd-test.patch b/compiler/rustc_codegen_gcc/patches/0024-core-Disable-portable-simd-test.patch
index 03900ba..d5fa1ce 100644
--- a/compiler/rustc_codegen_gcc/patches/0024-core-Disable-portable-simd-test.patch
+++ b/compiler/rustc_codegen_gcc/patches/0024-core-Disable-portable-simd-test.patch
@@ -7,167 +7,6 @@
  library/core/tests/lib.rs | 1 -
  1 file changed, 1 deletion(-)
 
-diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
-index aa1ad93..95fbf55 100644
---- a/library/core/src/lib.rs
-+++ b/library/core/src/lib.rs
-@@ -398,23 +398,4 @@ pub mod arch {
-     }
- }
- 
--// Pull in the `core_simd` crate directly into libcore. The contents of
--// `core_simd` are in a different repository: rust-lang/portable-simd.
--//
--// `core_simd` depends on libcore, but the contents of this module are
--// set up in such a way that directly pulling it here works such that the
--// crate uses this crate as its libcore.
--#[path = "../../portable-simd/crates/core_simd/src/mod.rs"]
--#[allow(missing_debug_implementations, dead_code, unsafe_op_in_unsafe_fn, unused_unsafe)]
--#[allow(rustdoc::bare_urls)]
--#[unstable(feature = "portable_simd", issue = "86656")]
--mod core_simd;
--
--#[doc = include_str!("../../portable-simd/crates/core_simd/src/core_simd_docs.md")]
--#[unstable(feature = "portable_simd", issue = "86656")]
--pub mod simd {
--    #[unstable(feature = "portable_simd", issue = "86656")]
--    pub use crate::core_simd::simd::*;
--}
--
- include!("primitive_docs.rs");
-diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs
-index cd38c3a..ad632dc 100644
---- a/library/core/src/slice/mod.rs
-+++ b/library/core/src/slice/mod.rs
-@@ -17,6 +17,5 @@ use crate::ptr;
- use crate::result::Result;
- use crate::result::Result::{Err, Ok};
--use crate::simd::{self, Simd};
- use crate::slice;
- 
- #[unstable(
-@@ -3475,121 +3474,6 @@ impl<T> [T] {
-         }
-     }
- 
--    /// Split a slice into a prefix, a middle of aligned SIMD types, and a suffix.
--    ///
--    /// This is a safe wrapper around [`slice::align_to`], so has the same weak
--    /// postconditions as that method.  You're only assured that
--    /// `self.len() == prefix.len() + middle.len() * LANES + suffix.len()`.
--    ///
--    /// Notably, all of the following are possible:
--    /// - `prefix.len() >= LANES`.
--    /// - `middle.is_empty()` despite `self.len() >= 3 * LANES`.
--    /// - `suffix.len() >= LANES`.
--    ///
--    /// That said, this is a safe method, so if you're only writing safe code,
--    /// then this can at most cause incorrect logic, not unsoundness.
--    ///
--    /// # Panics
--    ///
--    /// This will panic if the size of the SIMD type is different from
--    /// `LANES` times that of the scalar.
--    ///
--    /// At the time of writing, the trait restrictions on `Simd<T, LANES>` keeps
--    /// that from ever happening, as only power-of-two numbers of lanes are
--    /// supported.  It's possible that, in the future, those restrictions might
--    /// be lifted in a way that would make it possible to see panics from this
--    /// method for something like `LANES == 3`.
--    ///
--    /// # Examples
--    ///
--    /// ```
--    /// #![feature(portable_simd)]
--    ///
--    /// let short = &[1, 2, 3];
--    /// let (prefix, middle, suffix) = short.as_simd::<4>();
--    /// assert_eq!(middle, []); // Not enough elements for anything in the middle
--    ///
--    /// // They might be split in any possible way between prefix and suffix
--    /// let it = prefix.iter().chain(suffix).copied();
--    /// assert_eq!(it.collect::<Vec<_>>(), vec![1, 2, 3]);
--    ///
--    /// fn basic_simd_sum(x: &[f32]) -> f32 {
--    ///     use std::ops::Add;
--    ///     use std::simd::f32x4;
--    ///     let (prefix, middle, suffix) = x.as_simd();
--    ///     let sums = f32x4::from_array([
--    ///         prefix.iter().copied().sum(),
--    ///         0.0,
--    ///         0.0,
--    ///         suffix.iter().copied().sum(),
--    ///     ]);
--    ///     let sums = middle.iter().copied().fold(sums, f32x4::add);
--    ///     sums.reduce_sum()
--    /// }
--    ///
--    /// let numbers: Vec<f32> = (1..101).map(|x| x as _).collect();
--    /// assert_eq!(basic_simd_sum(&numbers[1..99]), 4949.0);
--    /// ```
--    #[unstable(feature = "portable_simd", issue = "86656")]
--    pub fn as_simd<const LANES: usize>(&self) -> (&[T], &[Simd<T, LANES>], &[T])
--    where
--        Simd<T, LANES>: AsRef<[T; LANES]>,
--        T: simd::SimdElement,
--        simd::LaneCount<LANES>: simd::SupportedLaneCount,
--    {
--        // These are expected to always match, as vector types are laid out like
--        // arrays per <https://llvm.org/docs/LangRef.html#vector-type>, but we
--        // might as well double-check since it'll optimize away anyhow.
--        assert_eq!(mem::size_of::<Simd<T, LANES>>(), mem::size_of::<[T; LANES]>());
--
--        // SAFETY: The simd types have the same layout as arrays, just with
--        // potentially-higher alignment, so the de-facto transmutes are sound.
--        unsafe { self.align_to() }
--    }
--
--    /// Split a slice into a prefix, a middle of aligned SIMD types, and a suffix.
--    ///
--    /// This is a safe wrapper around [`slice::align_to_mut`], so has the same weak
--    /// postconditions as that method.  You're only assured that
--    /// `self.len() == prefix.len() + middle.len() * LANES + suffix.len()`.
--    ///
--    /// Notably, all of the following are possible:
--    /// - `prefix.len() >= LANES`.
--    /// - `middle.is_empty()` despite `self.len() >= 3 * LANES`.
--    /// - `suffix.len() >= LANES`.
--    ///
--    /// That said, this is a safe method, so if you're only writing safe code,
--    /// then this can at most cause incorrect logic, not unsoundness.
--    ///
--    /// This is the mutable version of [`slice::as_simd`]; see that for examples.
--    ///
--    /// # Panics
--    ///
--    /// This will panic if the size of the SIMD type is different from
--    /// `LANES` times that of the scalar.
--    ///
--    /// At the time of writing, the trait restrictions on `Simd<T, LANES>` keeps
--    /// that from ever happening, as only power-of-two numbers of lanes are
--    /// supported.  It's possible that, in the future, those restrictions might
--    /// be lifted in a way that would make it possible to see panics from this
--    /// method for something like `LANES == 3`.
--    #[unstable(feature = "portable_simd", issue = "86656")]
--    pub fn as_simd_mut<const LANES: usize>(&mut self) -> (&mut [T], &mut [Simd<T, LANES>], &mut [T])
--    where
--        Simd<T, LANES>: AsMut<[T; LANES]>,
--        T: simd::SimdElement,
--        simd::LaneCount<LANES>: simd::SupportedLaneCount,
--    {
--        // These are expected to always match, as vector types are laid out like
--        // arrays per <https://llvm.org/docs/LangRef.html#vector-type>, but we
--        // might as well double-check since it'll optimize away anyhow.
--        assert_eq!(mem::size_of::<Simd<T, LANES>>(), mem::size_of::<[T; LANES]>());
--
--        // SAFETY: The simd types have the same layout as arrays, just with
--        // potentially-higher alignment, so the de-facto transmutes are sound.
--        unsafe { self.align_to_mut() }
--    }
--
-     /// Checks if the elements of this slice are sorted.
-     ///
-     /// That is, for each element `a` and its following element `b`, `a <= b` must hold. If the
 diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
 index 06c7be0..359e2e7 100644
 --- a/library/core/tests/lib.rs
@@ -188,41 +27,3 @@
  mod slice;
  mod str;
  mod str_lossy;
-diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
-index 5dc586d..b6fc48f 100644
---- a/library/std/src/lib.rs
-+++ b/library/std/src/lib.rs
-@@ -312,6 +312,5 @@
- #![feature(panic_can_unwind)]
- #![feature(panic_unwind)]
- #![feature(platform_intrinsics)]
--#![feature(portable_simd)]
- #![feature(prelude_import)]
- #![feature(ptr_as_uninit)]
-@@ -508,23 +508,6 @@ pub mod time;
- #[unstable(feature = "once_cell", issue = "74465")]
- pub mod lazy;
- 
--// Pull in `std_float` crate  into libstd. The contents of
--// `std_float` are in a different repository: rust-lang/portable-simd.
--#[path = "../../portable-simd/crates/std_float/src/lib.rs"]
--#[allow(missing_debug_implementations, dead_code, unsafe_op_in_unsafe_fn, unused_unsafe)]
--#[allow(rustdoc::bare_urls)]
--#[unstable(feature = "portable_simd", issue = "86656")]
--mod std_float;
--
--#[doc = include_str!("../../portable-simd/crates/core_simd/src/core_simd_docs.md")]
--#[unstable(feature = "portable_simd", issue = "86656")]
--pub mod simd {
--    #[doc(inline)]
--    pub use crate::std_float::StdFloat;
--    #[doc(inline)]
--    pub use core::simd::*;
--}
--
- #[stable(feature = "futures_api", since = "1.36.0")]
- pub mod task {
-     //! Types and Traits for working with asynchronous tasks.
---
-2.26.2.7.g19db9cfb68
-
diff --git a/compiler/rustc_codegen_gcc/prepare.sh b/compiler/rustc_codegen_gcc/prepare.sh
index 503fa29..e98f24c 100755
--- a/compiler/rustc_codegen_gcc/prepare.sh
+++ b/compiler/rustc_codegen_gcc/prepare.sh
@@ -1,10 +1,18 @@
-#!/bin/bash --verbose
+#!/usr/bin/env bash
 set -e
+set -v
 
 source prepare_build.sh
 
 cargo install hyperfine || echo "Skipping hyperfine install"
 
+git clone https://github.com/rust-random/rand.git || echo "rust-random/rand has already been cloned"
+pushd rand
+git checkout -- .
+git checkout 0f933f9c7176e53b2a3c7952ded484e1783f0bf1
+git am ../crate_patches/*-rand-*.patch
+popd
+
 git clone https://github.com/rust-lang/regex.git || echo "rust-lang/regex has already been cloned"
 pushd regex
 git checkout -- .
diff --git a/compiler/rustc_codegen_gcc/prepare_build.sh b/compiler/rustc_codegen_gcc/prepare_build.sh
index 3896775..8194360 100755
--- a/compiler/rustc_codegen_gcc/prepare_build.sh
+++ b/compiler/rustc_codegen_gcc/prepare_build.sh
@@ -1,4 +1,5 @@
-#!/bin/bash --verbose
+#!/usr/bin/env bash
 set -e
+set -v
 
 ./build_sysroot/prepare_sysroot_src.sh
diff --git a/compiler/rustc_codegen_gcc/rust-toolchain b/compiler/rustc_codegen_gcc/rust-toolchain
index db14ea2..b20aeb9 100644
--- a/compiler/rustc_codegen_gcc/rust-toolchain
+++ b/compiler/rustc_codegen_gcc/rust-toolchain
@@ -1,3 +1,3 @@
 [toolchain]
-channel = "nightly-2022-03-26"
+channel = "nightly-2022-06-06"
 components = ["rust-src", "rustc-dev", "llvm-tools-preview"]
diff --git a/compiler/rustc_codegen_gcc/rustc_patches/compile_test.patch b/compiler/rustc_codegen_gcc/rustc_patches/compile_test.patch
new file mode 100644
index 0000000..59143ea
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/rustc_patches/compile_test.patch
@@ -0,0 +1,14 @@
+diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs
+index 887d27fd6dca4..2c2239f2b83d1 100644
+--- a/src/tools/compiletest/src/header.rs
++++ b/src/tools/compiletest/src/header.rs
+@@ -806,8 +806,8 @@ pub fn make_test_description<R: Read>(
+     cfg: Option<&str>,
+ ) -> test::TestDesc {
+     let mut ignore = false;
+     #[cfg(not(bootstrap))]
+-    let ignore_message: Option<String> = None;
++    let ignore_message: Option<&str> = None;
+     let mut should_fail = false;
+
+     let rustc_has_profiler_support = env::var_os("RUSTC_PROFILER_SUPPORT").is_some();
diff --git a/compiler/rustc_codegen_gcc/rustup.sh b/compiler/rustc_codegen_gcc/rustup.sh
index 11d39a1..041079b 100755
--- a/compiler/rustc_codegen_gcc/rustup.sh
+++ b/compiler/rustc_codegen_gcc/rustup.sh
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
 
 set -e
 
diff --git a/compiler/rustc_codegen_gcc/src/archive.rs b/compiler/rustc_codegen_gcc/src/archive.rs
index fac532f..411ec27 100644
--- a/compiler/rustc_codegen_gcc/src/archive.rs
+++ b/compiler/rustc_codegen_gcc/src/archive.rs
@@ -32,7 +32,7 @@
 }
 
 impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> {
-    fn new(sess: &'a Session, output: &Path, input: Option<&Path>) -> Self {
+    fn new(sess: &'a Session, output: &Path) -> Self {
         let config = ArchiveConfig {
             sess,
             dst: output.to_path_buf(),
@@ -41,48 +41,13 @@
             use_gnu_style_archive: sess.target.options.archive_format == "gnu",
         };
 
-        let (src_archives, entries) = if let Some(input) = input {
-            let mut archive = ar::Archive::new(File::open(input).unwrap());
-            let mut entries = Vec::new();
-
-            let mut i = 0;
-            while let Some(entry) = archive.next_entry() {
-                let entry = entry.unwrap();
-                entries.push((
-                    String::from_utf8(entry.header().identifier().to_vec()).unwrap(),
-                    ArchiveEntry::FromArchive {
-                        archive_index: 0,
-                        entry_index: i,
-                    },
-                ));
-                i += 1;
-            }
-
-            (vec![(input.to_owned(), archive)], entries)
-        } else {
-            (vec![], Vec::new())
-        };
-
         ArArchiveBuilder {
             config,
-            src_archives,
-            entries,
+            src_archives: vec![],
+            entries: vec![],
         }
     }
 
-    fn src_files(&mut self) -> Vec<String> {
-        self.entries.iter().map(|(name, _)| name.clone()).collect()
-    }
-
-    fn remove_file(&mut self, name: &str) {
-        let index = self
-            .entries
-            .iter()
-            .position(|(entry_name, _)| entry_name == name)
-            .expect("Tried to remove file not existing in src archive");
-        self.entries.remove(index);
-    }
-
     fn add_file(&mut self, file: &Path) {
         self.entries.push((
             file.file_name().unwrap().to_str().unwrap().to_string(),
@@ -113,7 +78,7 @@
         Ok(())
     }
 
-    fn build(mut self) {
+    fn build(mut self) -> bool {
         use std::process::Command;
 
         fn add_file_using_ar(archive: &Path, file: &Path) {
@@ -146,6 +111,8 @@
             BuilderKind::Bsd(ar::Builder::new(File::create(&self.config.dst).unwrap()))
         };
 
+        let any_members = !self.entries.is_empty();
+
         // Add all files
         for (entry_name, entry) in self.entries.into_iter() {
             match entry {
@@ -206,6 +173,8 @@
         if !status.success() {
             self.config.sess.fatal(&format!("Ranlib exited with code {:?}", status.code()));
         }
+
+        any_members
     }
 
     fn inject_dll_import_lib(&mut self, _lib_name: &str, _dll_imports: &[DllImport], _tmpdir: &MaybeTempDir) {
diff --git a/compiler/rustc_codegen_gcc/src/asm.rs b/compiler/rustc_codegen_gcc/src/asm.rs
index 2e8cd93..52fd66a 100644
--- a/compiler/rustc_codegen_gcc/src/asm.rs
+++ b/compiler/rustc_codegen_gcc/src/asm.rs
@@ -13,6 +13,7 @@
 use crate::builder::Builder;
 use crate::context::CodegenCx;
 use crate::type_of::LayoutGccExt;
+use crate::callee::get_fn;
 
 
 // Rust asm! and GCC Extended Asm semantics differ substantially.
@@ -116,7 +117,6 @@
         let asm_arch = self.tcx.sess.asm_arch.unwrap();
         let is_x86 = matches!(asm_arch, InlineAsmArch::X86 | InlineAsmArch::X86_64);
         let att_dialect = is_x86 && options.contains(InlineAsmOptions::ATT_SYNTAX);
-        let intel_dialect = is_x86 && !options.contains(InlineAsmOptions::ATT_SYNTAX);
 
         // GCC index of an output operand equals its position in the array
         let mut outputs = vec![];
@@ -348,9 +348,24 @@
                     // processed in the previous pass
                 }
 
-                InlineAsmOperandRef::Const { .. }
-                | InlineAsmOperandRef::SymFn { .. }
-                | InlineAsmOperandRef::SymStatic { .. } => {
+                InlineAsmOperandRef::SymFn { instance } => {
+                    inputs.push(AsmInOperand {
+                        constraint: "X".into(),
+                        rust_idx,
+                        val: self.cx.rvalue_as_function(get_fn(self.cx, instance))
+                            .get_address(None),
+                    });
+                }
+
+                InlineAsmOperandRef::SymStatic { def_id } => {
+                    inputs.push(AsmInOperand {
+                        constraint: "X".into(),
+                        rust_idx,
+                        val: self.cx.get_static(def_id).get_address(None),
+                    });
+                }
+
+                InlineAsmOperandRef::Const { .. } => {
                     // processed in the previous pass
                 }
             }
@@ -359,7 +374,7 @@
         // 3. Build the template string
 
         let mut template_str = String::with_capacity(estimate_template_length(template, constants_len, att_dialect));
-        if !intel_dialect {
+        if att_dialect {
             template_str.push_str(ATT_SYNTAX_INS);
         }
 
@@ -444,7 +459,7 @@
             }
         }
 
-        if !intel_dialect {
+        if att_dialect {
             template_str.push_str(INTEL_SYNTAX_INS);
         }
 
@@ -588,11 +603,11 @@
             InlineAsmRegClass::X86(X86InlineAsmRegClass::xmm_reg)
             | InlineAsmRegClass::X86(X86InlineAsmRegClass::ymm_reg) => "x",
             InlineAsmRegClass::X86(X86InlineAsmRegClass::zmm_reg) => "v",
-            InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => unimplemented!(),
+            InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => "Yk",
             InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg0) => unimplemented!(),
             InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => unimplemented!(),
             InlineAsmRegClass::X86(
-                X86InlineAsmRegClass::x87_reg | X86InlineAsmRegClass::mmx_reg,
+                X86InlineAsmRegClass::x87_reg | X86InlineAsmRegClass::mmx_reg | X86InlineAsmRegClass::tmm_reg,
             ) => unreachable!("clobber-only"),
             InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => {
                 bug!("GCC backend does not support SPIR-V")
@@ -656,6 +671,7 @@
         InlineAsmRegClass::X86(X86InlineAsmRegClass::x87_reg) => unimplemented!(),
         InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => cx.type_i16(),
         InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg0) => cx.type_i16(),
+        InlineAsmRegClass::X86(X86InlineAsmRegClass::tmm_reg) => unimplemented!(),
         InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => cx.type_i32(),
         InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => {
             bug!("LLVM backend does not support SPIR-V")
@@ -671,8 +687,8 @@
         let asm_arch = self.tcx.sess.asm_arch.unwrap();
 
         // Default to Intel syntax on x86
-        let intel_syntax = matches!(asm_arch, InlineAsmArch::X86 | InlineAsmArch::X86_64)
-            && !options.contains(InlineAsmOptions::ATT_SYNTAX);
+        let att_dialect = matches!(asm_arch, InlineAsmArch::X86 | InlineAsmArch::X86_64)
+            && options.contains(InlineAsmOptions::ATT_SYNTAX);
 
         // Build the template string
         let mut template_str = String::new();
@@ -722,11 +738,11 @@
         }
 
         let template_str =
-            if intel_syntax {
-                format!("{}\n\t.intel_syntax noprefix", template_str)
+            if att_dialect {
+                format!(".att_syntax\n\t{}\n\t.intel_syntax noprefix", template_str)
             }
             else {
-                format!(".att_syntax\n\t{}\n\t.intel_syntax noprefix", template_str)
+                template_str
             };
         // NOTE: seems like gcc will put the asm in the wrong section, so set it to .text manually.
         let template_str = format!(".pushsection .text\n{}\n.popsection", template_str);
@@ -787,7 +803,7 @@
         },
         InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => None,
         InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg0) => None,
-        InlineAsmRegClass::X86(X86InlineAsmRegClass::x87_reg | X86InlineAsmRegClass::mmx_reg) => {
+        InlineAsmRegClass::X86(X86InlineAsmRegClass::x87_reg | X86InlineAsmRegClass::mmx_reg | X86InlineAsmRegClass::tmm_reg) => {
             unreachable!("clobber-only")
         }
         InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => unimplemented!(),
diff --git a/compiler/rustc_codegen_gcc/src/base.rs b/compiler/rustc_codegen_gcc/src/base.rs
index f5aca35..e4ecbd4 100644
--- a/compiler/rustc_codegen_gcc/src/base.rs
+++ b/compiler/rustc_codegen_gcc/src/base.rs
@@ -78,9 +78,19 @@
         let context = Context::default();
         // TODO(antoyo): only set on x86 platforms.
         context.add_command_line_option("-masm=intel");
+        // TODO(antoyo): only add the following cli argument if the feature is supported.
+        context.add_command_line_option("-msse2");
+        context.add_command_line_option("-mavx2");
+        context.add_command_line_option("-msha");
+        context.add_command_line_option("-mpclmul");
+        // FIXME(antoyo): the following causes an illegal instruction on vmovdqu64 in std_example on my CPU.
+        // Only add if the CPU supports it.
+        //context.add_command_line_option("-mavx512f");
         for arg in &tcx.sess.opts.cg.llvm_args {
             context.add_command_line_option(arg);
         }
+        // NOTE: This is needed to compile the file src/intrinsic/archs.rs during a bootstrap of rustc.
+        context.add_command_line_option("-fno-var-tracking-assignments");
         // NOTE: an optimization (https://github.com/rust-lang/rustc_codegen_gcc/issues/53).
         context.add_command_line_option("-fno-semantic-interposition");
         // NOTE: Rust relies on LLVM not doing TBAA (https://github.com/rust-lang/unsafe-code-guidelines/issues/292).
diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs
index 41f88f1..fa490fe 100644
--- a/compiler/rustc_codegen_gcc/src/builder.rs
+++ b/compiler/rustc_codegen_gcc/src/builder.rs
@@ -3,11 +3,11 @@
 use std::convert::TryFrom;
 use std::ops::Deref;
 
-use gccjit::FunctionType;
 use gccjit::{
     BinaryOp,
     Block,
     ComparisonOp,
+    Context,
     Function,
     LValue,
     RValue,
@@ -48,6 +48,7 @@
 
 use crate::common::{SignType, TypeReflection, type_is_pointer};
 use crate::context::CodegenCx;
+use crate::intrinsic::llvm;
 use crate::type_of::LayoutGccExt;
 
 // TODO(antoyo)
@@ -61,24 +62,6 @@
     Min,
 }
 
-trait EnumClone {
-    fn clone(&self) -> Self;
-}
-
-impl EnumClone for AtomicOrdering {
-    fn clone(&self) -> Self {
-        match *self {
-            AtomicOrdering::NotAtomic => AtomicOrdering::NotAtomic,
-            AtomicOrdering::Unordered => AtomicOrdering::Unordered,
-            AtomicOrdering::Monotonic => AtomicOrdering::Monotonic,
-            AtomicOrdering::Acquire => AtomicOrdering::Acquire,
-            AtomicOrdering::Release => AtomicOrdering::Release,
-            AtomicOrdering::AcquireRelease => AtomicOrdering::AcquireRelease,
-            AtomicOrdering::SequentiallyConsistent => AtomicOrdering::SequentiallyConsistent,
-        }
-    }
-}
-
 pub struct Builder<'a: 'gcc, 'gcc, 'tcx> {
     pub cx: &'a CodegenCx<'gcc, 'tcx>,
     pub block: Block<'gcc>,
@@ -103,9 +86,9 @@
             match order {
                 // TODO(antoyo): does this make sense?
                 AtomicOrdering::AcquireRelease | AtomicOrdering::Release => AtomicOrdering::Acquire,
-                _ => order.clone(),
+                _ => order,
             };
-        let previous_value = self.atomic_load(dst.get_type(), dst, load_ordering.clone(), Size::from_bytes(size));
+        let previous_value = self.atomic_load(dst.get_type(), dst, load_ordering, Size::from_bytes(size));
         let previous_var = func.new_local(None, previous_value.get_type(), "previous_value");
         let return_value = func.new_local(None, previous_value.get_type(), "return_value");
         self.llbb().add_assignment(None, previous_var, previous_value);
@@ -217,17 +200,28 @@
             return Cow::Borrowed(args);
         }
 
+        let func_name = format!("{:?}", func_ptr);
+
         let casted_args: Vec<_> = param_types
             .into_iter()
             .zip(args.iter())
             .enumerate()
             .map(|(index, (expected_ty, &actual_val))| {
+                if llvm::ignore_arg_cast(&func_name, index, args.len()) {
+                    return actual_val;
+                }
+
                 let actual_ty = actual_val.get_type();
                 if expected_ty != actual_ty {
-                    if on_stack_param_indices.contains(&index) {
+                    if !actual_ty.is_vector() && !expected_ty.is_vector() && actual_ty.is_integral() && expected_ty.is_integral() && actual_ty.get_size() != expected_ty.get_size() {
+                        self.context.new_cast(None, actual_val, expected_ty)
+                    }
+                    else if on_stack_param_indices.contains(&index) {
                         actual_val.dereference(None).to_rvalue()
                     }
                     else {
+                        assert!(!((actual_ty.is_vector() && !expected_ty.is_vector()) || (!actual_ty.is_vector() && expected_ty.is_vector())), "{:?} ({}) -> {:?} ({}), index: {:?}[{}]", actual_ty, actual_ty.is_vector(), expected_ty, expected_ty.is_vector(), func_ptr, index);
+                        // TODO(antoyo): perhaps use __builtin_convertvector for vector casting.
                         self.bitcast(actual_val, expected_ty)
                     }
                 }
@@ -286,22 +280,20 @@
         // gccjit requires to use the result of functions, even when it's not used.
         // That's why we assign the result to a local or call add_eval().
         let gcc_func = func_ptr.get_type().dyncast_function_ptr_type().expect("function ptr");
-        let mut return_type = gcc_func.get_return_type();
+        let return_type = gcc_func.get_return_type();
         let void_type = self.context.new_type::<()>();
         let current_func = self.block.get_function();
 
-        // FIXME(antoyo): As a temporary workaround for unsupported LLVM intrinsics.
-        if gcc_func.get_param_count() == 0 && format!("{:?}", func_ptr) == "__builtin_ia32_pmovmskb128" {
-            return_type = self.int_type;
-        }
-
         if return_type != void_type {
             unsafe { RETURN_VALUE_COUNT += 1 };
             let result = current_func.new_local(None, return_type, &format!("ptrReturnValue{}", unsafe { RETURN_VALUE_COUNT }));
+            let func_name = format!("{:?}", func_ptr);
+            let args = llvm::adjust_intrinsic_arguments(&self, gcc_func, args, &func_name);
             self.block.add_assignment(None, result, self.cx.context.new_call_through_ptr(None, func_ptr, &args));
             result.to_rvalue()
         }
         else {
+            #[cfg(not(feature="master"))]
             if gcc_func.get_param_count() == 0 {
                 // FIXME(antoyo): As a temporary workaround for unsupported LLVM intrinsics.
                 self.block.add_eval(None, self.cx.context.new_call_through_ptr(None, func_ptr, &[]));
@@ -309,6 +301,8 @@
             else {
                 self.block.add_eval(None, self.cx.context.new_call_through_ptr(None, func_ptr, &args));
             }
+            #[cfg(feature="master")]
+            self.block.add_eval(None, self.cx.context.new_call_through_ptr(None, func_ptr, &args));
             // Return dummy value when not having return value.
             let result = current_func.new_local(None, self.isize_type, "dummyValueThatShouldNeverBeUsed");
             self.block.add_assignment(None, result, self.context.new_rvalue_from_long(self.isize_type, 0));
@@ -498,8 +492,11 @@
     }
 
     fn exactudiv(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
-        // TODO(antoyo): convert the arguments to unsigned?
         // TODO(antoyo): poison if not exact.
+        let a_type = a.get_type().to_unsigned(self);
+        let a = self.gcc_int_cast(a, a_type);
+        let b_type = b.get_type().to_unsigned(self);
+        let b = self.gcc_int_cast(b, b_type);
         a / b
     }
 
@@ -529,12 +526,12 @@
     }
 
     fn frem(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
-        if a.get_type() == self.cx.float_type {
+        if a.get_type().is_compatible_with(self.cx.float_type) {
             let fmodf = self.context.get_builtin_function("fmodf");
             // FIXME(antoyo): this seems to produce the wrong result.
             return self.context.new_call(None, fmodf, &[a, b]);
         }
-        assert_eq!(a.get_type(), self.cx.double_type);
+        assert_eq!(a.get_type().unqualified(), self.cx.double_type);
 
         let fmod = self.context.get_builtin_function("fmod");
         return self.context.new_call(None, fmod, &[a, b]);
@@ -650,18 +647,17 @@
         unimplemented!();
     }
 
-    fn load(&mut self, _ty: Type<'gcc>, ptr: RValue<'gcc>, _align: Align) -> RValue<'gcc> {
-        // TODO(antoyo): use ty.
+    fn load(&mut self, pointee_ty: Type<'gcc>, ptr: RValue<'gcc>, _align: Align) -> RValue<'gcc> {
         let block = self.llbb();
         let function = block.get_function();
         // NOTE: instead of returning the dereference here, we have to assign it to a variable in
         // the current basic block. Otherwise, it could be used in another basic block, causing a
         // dereference after a drop, for instance.
-        // TODO(antoyo): handle align.
+        // TODO(antoyo): handle align of the load instruction.
+        let ptr = self.context.new_cast(None, ptr, pointee_ty.make_pointer());
         let deref = ptr.dereference(None).to_rvalue();
-        let value_type = deref.get_type();
         unsafe { RETURN_VALUE_COUNT += 1 };
-        let loaded_value = function.new_local(None, value_type, &format!("loadedValue{}", unsafe { RETURN_VALUE_COUNT }));
+        let loaded_value = function.new_local(None, pointee_ty, &format!("loadedValue{}", unsafe { RETURN_VALUE_COUNT }));
         block.add_assignment(None, loaded_value, deref);
         loaded_value.to_rvalue()
     }
@@ -713,7 +709,11 @@
                 OperandValue::Ref(place.llval, Some(llextra), place.align)
             }
             else if place.layout.is_gcc_immediate() {
-                let load = self.load(place.llval.get_type(), place.llval, place.align);
+                let load = self.load(
+                    place.layout.gcc_type(self, false),
+                    place.llval,
+                    place.align,
+                );
                 if let abi::Abi::Scalar(ref scalar) = place.layout.abi {
                     scalar_load_metadata(self, load, scalar);
                 }
@@ -725,7 +725,8 @@
 
                 let mut load = |i, scalar: &abi::Scalar, align| {
                     let llptr = self.struct_gep(pair_type, place.llval, i as u64);
-                    let load = self.load(llptr.get_type(), llptr, align);
+                    let llty = place.layout.scalar_pair_element_gcc_type(self, i, false);
+                    let load = self.load(llty, llptr, align);
                     scalar_load_metadata(self, load, scalar);
                     if scalar.is_bool() { self.trunc(load, self.type_i1()) } else { load }
                 };
@@ -797,9 +798,16 @@
         self.store_with_flags(val, ptr, align, MemFlags::empty())
     }
 
-    fn store_with_flags(&mut self, val: RValue<'gcc>, ptr: RValue<'gcc>, _align: Align, _flags: MemFlags) -> RValue<'gcc> {
+    fn store_with_flags(&mut self, val: RValue<'gcc>, ptr: RValue<'gcc>, align: Align, _flags: MemFlags) -> RValue<'gcc> {
         let ptr = self.check_store(val, ptr);
-        self.llbb().add_assignment(None, ptr.dereference(None), val);
+        let destination = ptr.dereference(None);
+        // NOTE: libgccjit does not support specifying the alignment on the assignment, so we cast
+        // to type so it gets the proper alignment.
+        let destination_type = destination.to_rvalue().get_type().unqualified();
+        let aligned_type = destination_type.get_aligned(align.bytes()).make_pointer();
+        let aligned_destination = self.cx.context.new_bitcast(None, ptr, aligned_type);
+        let aligned_destination = aligned_destination.dereference(None);
+        self.llbb().add_assignment(None, aligned_destination, val);
         // TODO(antoyo): handle align and flags.
         // NOTE: dummy value here since it's never used. FIXME(antoyo): API should not return a value here?
         self.cx.context.new_rvalue_zero(self.type_i32())
@@ -971,7 +979,7 @@
     fn memmove(&mut self, dst: RValue<'gcc>, dst_align: Align, src: RValue<'gcc>, src_align: Align, size: RValue<'gcc>, flags: MemFlags) {
         if flags.contains(MemFlags::NONTEMPORAL) {
             // HACK(nox): This is inefficient but there is no nontemporal memmove.
-            let val = self.load(src.get_type(), src, src_align);
+            let val = self.load(src.get_type().get_pointee().expect("get_pointee"), src, src_align);
             let ptr = self.pointercast(dst, self.type_ptr_to(self.val_ty(val)));
             self.store_with_flags(val, ptr, dst_align, flags);
             return;
@@ -1287,16 +1295,183 @@
 }
 
 impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
+    #[cfg(feature="master")]
     pub fn shuffle_vector(&mut self, v1: RValue<'gcc>, v2: RValue<'gcc>, mask: RValue<'gcc>) -> RValue<'gcc> {
-        let return_type = v1.get_type();
-        let params = [
-            self.context.new_parameter(None, return_type, "v1"),
-            self.context.new_parameter(None, return_type, "v2"),
-            self.context.new_parameter(None, mask.get_type(), "mask"),
-        ];
-        let shuffle = self.context.new_function(None, FunctionType::Extern, return_type, &params, "_mm_shuffle_epi8", false);
-        self.context.new_call(None, shuffle, &[v1, v2, mask])
+        let struct_type = mask.get_type().is_struct().expect("mask of struct type");
+
+        // TODO(antoyo): use a recursive unqualified() here.
+        let vector_type = v1.get_type().unqualified().dyncast_vector().expect("vector type");
+        let element_type = vector_type.get_element_type();
+        let vec_num_units = vector_type.get_num_units();
+
+        let mask_num_units = struct_type.get_field_count();
+        let mut vector_elements = vec![];
+        let mask_element_type =
+            if element_type.is_integral() {
+                element_type
+            }
+            else {
+                #[cfg(feature="master")]
+                {
+                    self.cx.type_ix(element_type.get_size() as u64 * 8)
+                }
+                #[cfg(not(feature="master"))]
+                self.int_type
+            };
+        for i in 0..mask_num_units {
+            let field = struct_type.get_field(i as i32);
+            vector_elements.push(self.context.new_cast(None, mask.access_field(None, field).to_rvalue(), mask_element_type));
+        }
+
+        // NOTE: the mask needs to be the same length as the input vectors, so add the missing
+        // elements in the mask if needed.
+        for _ in mask_num_units..vec_num_units {
+            vector_elements.push(self.context.new_rvalue_zero(mask_element_type));
+        }
+
+        let array_type = self.context.new_array_type(None, element_type, vec_num_units as i32);
+        let result_type = self.context.new_vector_type(element_type, mask_num_units as u64);
+        let (v1, v2) =
+            if vec_num_units < mask_num_units {
+                // NOTE: the mask needs to be the same length as the input vectors, so join the 2
+                // vectors and create a dummy second vector.
+                // TODO(antoyo): switch to using new_vector_access.
+                let array = self.context.new_bitcast(None, v1, array_type);
+                let mut elements = vec![];
+                for i in 0..vec_num_units {
+                    elements.push(self.context.new_array_access(None, array, self.context.new_rvalue_from_int(self.int_type, i as i32)).to_rvalue());
+                }
+                // TODO(antoyo): switch to using new_vector_access.
+                let array = self.context.new_bitcast(None, v2, array_type);
+                for i in 0..(mask_num_units - vec_num_units) {
+                    elements.push(self.context.new_array_access(None, array, self.context.new_rvalue_from_int(self.int_type, i as i32)).to_rvalue());
+                }
+                let v1 = self.context.new_rvalue_from_vector(None, result_type, &elements);
+                let zero = self.context.new_rvalue_zero(element_type);
+                let v2 = self.context.new_rvalue_from_vector(None, result_type, &vec![zero; mask_num_units]);
+                (v1, v2)
+            }
+            else {
+                (v1, v2)
+            };
+
+        let new_mask_num_units = std::cmp::max(mask_num_units, vec_num_units);
+        let mask_type = self.context.new_vector_type(mask_element_type, new_mask_num_units as u64);
+        let mask = self.context.new_rvalue_from_vector(None, mask_type, &vector_elements);
+        let result = self.context.new_rvalue_vector_perm(None, v1, v2, mask);
+
+        if vec_num_units != mask_num_units {
+            // NOTE: if padding was added, only select the number of elements of the masks to
+            // remove that padding in the result.
+            let mut elements = vec![];
+            // TODO(antoyo): switch to using new_vector_access.
+            let array = self.context.new_bitcast(None, result, array_type);
+            for i in 0..mask_num_units {
+                elements.push(self.context.new_array_access(None, array, self.context.new_rvalue_from_int(self.int_type, i as i32)).to_rvalue());
+            }
+            self.context.new_rvalue_from_vector(None, result_type, &elements)
+        }
+        else {
+            result
+        }
     }
+
+    #[cfg(not(feature="master"))]
+    pub fn shuffle_vector(&mut self, _v1: RValue<'gcc>, _v2: RValue<'gcc>, _mask: RValue<'gcc>) -> RValue<'gcc> {
+        unimplemented!();
+    }
+
+    #[cfg(feature="master")]
+    pub fn vector_reduce<F>(&mut self, src: RValue<'gcc>, op: F) -> RValue<'gcc>
+    where F: Fn(RValue<'gcc>, RValue<'gcc>, &'gcc Context<'gcc>) -> RValue<'gcc>
+    {
+        let vector_type = src.get_type().unqualified().dyncast_vector().expect("vector type");
+        let element_count = vector_type.get_num_units();
+        let mut vector_elements = vec![];
+        for i in 0..element_count {
+            vector_elements.push(i);
+        }
+        let mask_type = self.context.new_vector_type(self.int_type, element_count as u64);
+        let mut shift = 1;
+        let mut res = src;
+        while shift < element_count {
+            let vector_elements: Vec<_> =
+                vector_elements.iter()
+                    .map(|i| self.context.new_rvalue_from_int(self.int_type, ((i + shift) % element_count) as i32))
+                    .collect();
+            let mask = self.context.new_rvalue_from_vector(None, mask_type, &vector_elements);
+            let shifted = self.context.new_rvalue_vector_perm(None, res, res, mask);
+            shift *= 2;
+            res = op(res, shifted, &self.context);
+        }
+        self.context.new_vector_access(None, res, self.context.new_rvalue_zero(self.int_type))
+            .to_rvalue()
+    }
+
+    #[cfg(not(feature="master"))]
+    pub fn vector_reduce<F>(&mut self, src: RValue<'gcc>, op: F) -> RValue<'gcc>
+    where F: Fn(RValue<'gcc>, RValue<'gcc>, &'gcc Context<'gcc>) -> RValue<'gcc>
+    {
+        unimplemented!();
+    }
+
+    pub fn vector_reduce_op(&mut self, src: RValue<'gcc>, op: BinaryOp) -> RValue<'gcc> {
+        self.vector_reduce(src, |a, b, context| context.new_binary_op(None, op, a.get_type(), a, b))
+    }
+
+    pub fn vector_reduce_fadd_fast(&mut self, _acc: RValue<'gcc>, _src: RValue<'gcc>) -> RValue<'gcc> {
+        unimplemented!();
+    }
+
+    pub fn vector_reduce_fmul_fast(&mut self, _acc: RValue<'gcc>, _src: RValue<'gcc>) -> RValue<'gcc> {
+        unimplemented!();
+    }
+
+    // Inspired by Hacker's Delight min implementation.
+    pub fn vector_reduce_min(&mut self, src: RValue<'gcc>) -> RValue<'gcc> {
+        self.vector_reduce(src, |a, b, context| {
+            let differences_or_zeros = difference_or_zero(a, b, context);
+            context.new_binary_op(None, BinaryOp::Minus, a.get_type(), a, differences_or_zeros)
+        })
+    }
+
+    // Inspired by Hacker's Delight max implementation.
+    pub fn vector_reduce_max(&mut self, src: RValue<'gcc>) -> RValue<'gcc> {
+        self.vector_reduce(src, |a, b, context| {
+            let differences_or_zeros = difference_or_zero(a, b, context);
+            context.new_binary_op(None, BinaryOp::Plus, b.get_type(), b, differences_or_zeros)
+        })
+    }
+
+    pub fn vector_select(&mut self, cond: RValue<'gcc>, then_val: RValue<'gcc>, else_val: RValue<'gcc>) -> RValue<'gcc> {
+        // cond is a vector of integers, not of bools.
+        let cond_type = cond.get_type();
+        let vector_type = cond_type.unqualified().dyncast_vector().expect("vector type");
+        let num_units = vector_type.get_num_units();
+        let element_type = vector_type.get_element_type();
+        let zeros = vec![self.context.new_rvalue_zero(element_type); num_units];
+        let zeros = self.context.new_rvalue_from_vector(None, cond_type, &zeros);
+
+        let masks = self.context.new_comparison(None, ComparisonOp::NotEquals, cond, zeros);
+        let then_vals = masks & then_val;
+
+        let ones = vec![self.context.new_rvalue_one(element_type); num_units];
+        let ones = self.context.new_rvalue_from_vector(None, cond_type, &ones);
+        let inverted_masks = masks + ones;
+        // NOTE: sometimes, the type of else_val can be different than the type of then_val in
+        // libgccjit (vector of int vs vector of int32_t), but they should be the same for the AND
+        // operation to work.
+        let else_val = self.context.new_bitcast(None, else_val, then_val.get_type());
+        let else_vals = inverted_masks & else_val;
+
+        then_vals | else_vals
+    }
+}
+
+fn difference_or_zero<'gcc>(a: RValue<'gcc>, b: RValue<'gcc>, context: &'gcc Context<'gcc>) -> RValue<'gcc> {
+    let difference = a - b;
+    let masks = context.new_comparison(None, ComparisonOp::GreaterThanEquals, b, a);
+    difference & masks
 }
 
 impl<'a, 'gcc, 'tcx> StaticBuilderMethods for Builder<'a, 'gcc, 'tcx> {
@@ -1384,9 +1559,8 @@
 
         let ordering =
             match self {
-                AtomicOrdering::NotAtomic => __ATOMIC_RELAXED, // TODO(antoyo): check if that's the same.
                 AtomicOrdering::Unordered => __ATOMIC_RELAXED,
-                AtomicOrdering::Monotonic => __ATOMIC_RELAXED, // TODO(antoyo): check if that's the same.
+                AtomicOrdering::Relaxed => __ATOMIC_RELAXED, // TODO(antoyo): check if that's the same.
                 AtomicOrdering::Acquire => __ATOMIC_ACQUIRE,
                 AtomicOrdering::Release => __ATOMIC_RELEASE,
                 AtomicOrdering::AcquireRelease => __ATOMIC_ACQ_REL,
diff --git a/compiler/rustc_codegen_gcc/src/common.rs b/compiler/rustc_codegen_gcc/src/common.rs
index b056b6d..ce34140 100644
--- a/compiler/rustc_codegen_gcc/src/common.rs
+++ b/compiler/rustc_codegen_gcc/src/common.rs
@@ -121,8 +121,8 @@
         unimplemented!();
     }
 
-    fn const_real(&self, _t: Type<'gcc>, _val: f64) -> RValue<'gcc> {
-        unimplemented!();
+    fn const_real(&self, typ: Type<'gcc>, val: f64) -> RValue<'gcc> {
+        self.context.new_rvalue_from_double(typ, val)
     }
 
     fn const_str(&self, s: Symbol) -> (RValue<'gcc>, RValue<'gcc>) {
@@ -279,6 +279,21 @@
         else if self.is_u128(cx) {
             cx.i128_type
         }
+        else if self.is_uchar(cx) {
+            cx.char_type
+        }
+        else if self.is_ushort(cx) {
+            cx.short_type
+        }
+        else if self.is_uint(cx) {
+            cx.int_type
+        }
+        else if self.is_ulong(cx) {
+            cx.long_type
+        }
+        else if self.is_ulonglong(cx) {
+            cx.longlong_type
+        }
         else {
             self.clone()
         }
@@ -300,6 +315,21 @@
         else if self.is_i128(cx) {
             cx.u128_type
         }
+        else if self.is_char(cx) {
+            cx.uchar_type
+        }
+        else if self.is_short(cx) {
+            cx.ushort_type
+        }
+        else if self.is_int(cx) {
+            cx.uint_type
+        }
+        else if self.is_long(cx) {
+            cx.ulong_type
+        }
+        else if self.is_longlong(cx) {
+            cx.ulonglong_type
+        }
         else {
             self.clone()
         }
@@ -312,6 +342,11 @@
     fn is_uint(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
     fn is_ulong(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
     fn is_ulonglong(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
+    fn is_char(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
+    fn is_short(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
+    fn is_int(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
+    fn is_long(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
+    fn is_longlong(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
 
     fn is_i8(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
     fn is_u8(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
@@ -326,15 +361,17 @@
 
     fn is_f32(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
     fn is_f64(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
+
+    fn is_vector(&self) -> bool;
 }
 
 impl<'gcc, 'tcx> TypeReflection<'gcc, 'tcx> for Type<'gcc> {
     fn is_uchar(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
-        self.unqualified() == cx.u8_type
+        self.unqualified() == cx.uchar_type
     }
 
     fn is_ushort(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
-        self.unqualified() == cx.u16_type
+        self.unqualified() == cx.ushort_type
     }
 
     fn is_uint(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
@@ -349,6 +386,26 @@
         self.unqualified() == cx.ulonglong_type
     }
 
+    fn is_char(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
+        self.unqualified() == cx.char_type
+    }
+
+    fn is_short(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
+        self.unqualified() == cx.short_type
+    }
+
+    fn is_int(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
+        self.unqualified() == cx.int_type
+    }
+
+    fn is_long(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
+        self.unqualified() == cx.long_type
+    }
+
+    fn is_longlong(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
+        self.unqualified() == cx.longlong_type
+    }
+
     fn is_i8(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
         self.unqualified() == cx.i8_type
     }
@@ -396,4 +453,21 @@
     fn is_f64(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
         self.unqualified() == cx.context.new_type::<f64>()
     }
+
+    fn is_vector(&self) -> bool {
+        let mut typ = self.clone();
+        loop {
+            if typ.dyncast_vector().is_some() {
+                return true;
+            }
+
+            let old_type = typ;
+            typ = typ.unqualified();
+            if old_type == typ {
+                break;
+            }
+        }
+
+        false
+    }
 }
diff --git a/compiler/rustc_codegen_gcc/src/consts.rs b/compiler/rustc_codegen_gcc/src/consts.rs
index 3dc456f..c0b8d21 100644
--- a/compiler/rustc_codegen_gcc/src/consts.rs
+++ b/compiler/rustc_codegen_gcc/src/consts.rs
@@ -25,7 +25,9 @@
                 }
             }
         }
-        self.context.new_bitcast(None, value, typ)
+        // NOTE: since bitcast makes a value non-constant, don't bitcast if not necessary as some
+        // SIMD builtins require a constant value.
+        self.bitcast_if_needed(value, typ)
     }
 }
 
@@ -45,7 +47,10 @@
             }
         }
         let global_value = self.static_addr_of_mut(cv, align, kind);
-        // TODO(antoyo): set global constant.
+        #[cfg(feature = "master")]
+        self.global_lvalues.borrow().get(&global_value)
+            .expect("`static_addr_of_mut` did not add the global to `self.global_lvalues`")
+            .global_set_readonly();
         self.const_globals.borrow_mut().insert(cv, global_value);
         global_value
     }
@@ -79,20 +84,15 @@
 
         // TODO(antoyo): set alignment.
 
-        let value =
-            if value.get_type() != gcc_type {
-                self.context.new_bitcast(None, value, gcc_type)
-            }
-            else {
-                value
-            };
+        let value = self.bitcast_if_needed(value, gcc_type);
         global.global_set_initializer_rvalue(value);
 
         // As an optimization, all shared statics which do not have interior
         // mutability are placed into read-only memory.
         if !is_mutable {
             if self.type_is_freeze(ty) {
-                // TODO(antoyo): set global constant.
+                #[cfg(feature = "master")]
+                global.global_set_readonly();
             }
         }
 
@@ -171,8 +171,9 @@
                 Some(kind) if !self.tcx.sess.fewer_names() => {
                     let name = self.generate_local_symbol_name(kind);
                     // TODO(antoyo): check if it's okay that no link_section is set.
-                    // TODO(antoyo): set alignment here as well.
-                    let global = self.declare_private_global(&name[..], self.val_ty(cv));
+
+                    let typ = self.val_ty(cv).get_aligned(align.bytes());
+                    let global = self.declare_private_global(&name[..], typ);
                     global
                 }
                 _ => {
diff --git a/compiler/rustc_codegen_gcc/src/context.rs b/compiler/rustc_codegen_gcc/src/context.rs
index edbe712..44f36cf 100644
--- a/compiler/rustc_codegen_gcc/src/context.rs
+++ b/compiler/rustc_codegen_gcc/src/context.rs
@@ -35,6 +35,7 @@
     pub normal_function_addresses: RefCell<FxHashSet<RValue<'gcc>>>,
 
     pub functions: RefCell<FxHashMap<String, Function<'gcc>>>,
+    pub intrinsics: RefCell<FxHashMap<String, Function<'gcc>>>,
 
     pub tls_model: gccjit::TlsModel,
 
@@ -53,10 +54,15 @@
     pub u128_type: Type<'gcc>,
     pub usize_type: Type<'gcc>,
 
+    pub char_type: Type<'gcc>,
+    pub uchar_type: Type<'gcc>,
+    pub short_type: Type<'gcc>,
+    pub ushort_type: Type<'gcc>,
     pub int_type: Type<'gcc>,
     pub uint_type: Type<'gcc>,
     pub long_type: Type<'gcc>,
     pub ulong_type: Type<'gcc>,
+    pub longlong_type: Type<'gcc>,
     pub ulonglong_type: Type<'gcc>,
     pub sizet_type: Type<'gcc>,
 
@@ -145,10 +151,15 @@
         let float_type = context.new_type::<f32>();
         let double_type = context.new_type::<f64>();
 
+        let char_type = context.new_c_type(CType::Char);
+        let uchar_type = context.new_c_type(CType::UChar);
+        let short_type = context.new_c_type(CType::Short);
+        let ushort_type = context.new_c_type(CType::UShort);
         let int_type = context.new_c_type(CType::Int);
         let uint_type = context.new_c_type(CType::UInt);
         let long_type = context.new_c_type(CType::Long);
         let ulong_type = context.new_c_type(CType::ULong);
+        let longlong_type = context.new_c_type(CType::LongLong);
         let ulonglong_type = context.new_c_type(CType::ULongLong);
         let sizet_type = context.new_c_type(CType::SizeT);
 
@@ -184,6 +195,7 @@
             current_func: RefCell::new(None),
             normal_function_addresses: Default::default(),
             functions: RefCell::new(functions),
+            intrinsics: RefCell::new(FxHashMap::default()),
 
             tls_model,
 
@@ -200,10 +212,15 @@
             u32_type,
             u64_type,
             u128_type,
+            char_type,
+            uchar_type,
+            short_type,
+            ushort_type,
             int_type,
             uint_type,
             long_type,
             ulong_type,
+            longlong_type,
             ulonglong_type,
             sizet_type,
 
@@ -269,16 +286,25 @@
     }
 
     pub fn is_native_int_type_or_bool(&self, typ: Type<'gcc>) -> bool {
-        self.is_native_int_type(typ) || typ == self.bool_type
+        self.is_native_int_type(typ) || typ.is_compatible_with(self.bool_type)
     }
 
     pub fn is_int_type_or_bool(&self, typ: Type<'gcc>) -> bool {
-        self.is_native_int_type(typ) || self.is_non_native_int_type(typ) || typ == self.bool_type
+        self.is_native_int_type(typ) || self.is_non_native_int_type(typ) || typ.is_compatible_with(self.bool_type)
     }
 
     pub fn sess(&self) -> &Session {
         &self.tcx.sess
     }
+
+    pub fn bitcast_if_needed(&self, value: RValue<'gcc>, expected_type: Type<'gcc>) -> RValue<'gcc> {
+        if value.get_type() != expected_type {
+            self.context.new_bitcast(None, value, expected_type)
+        }
+        else {
+            value
+        }
+    }
 }
 
 impl<'gcc, 'tcx> BackendTypes for CodegenCx<'gcc, 'tcx> {
@@ -306,8 +332,16 @@
     }
 
     fn get_fn_addr(&self, instance: Instance<'tcx>) -> RValue<'gcc> {
-        let func = get_fn(self, instance);
-        let func = self.rvalue_as_function(func);
+        let func_name = self.tcx.symbol_name(instance).name;
+
+        let func =
+            if self.intrinsics.borrow().contains_key(func_name) {
+                self.intrinsics.borrow()[func_name].clone()
+            }
+            else {
+                let func = get_fn(self, instance);
+                self.rvalue_as_function(func)
+            };
         let ptr = func.get_address(None);
 
         // TODO(antoyo): don't do this twice: i.e. in declare_fn and here.
diff --git a/compiler/rustc_codegen_gcc/src/declare.rs b/compiler/rustc_codegen_gcc/src/declare.rs
index 4301737..a619e2f 100644
--- a/compiler/rustc_codegen_gcc/src/declare.rs
+++ b/compiler/rustc_codegen_gcc/src/declare.rs
@@ -11,7 +11,7 @@
 impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
     pub fn get_or_insert_global(&self, name: &str, ty: Type<'gcc>, is_tls: bool, link_section: Option<Symbol>) -> LValue<'gcc> {
         if self.globals.borrow().contains_key(name) {
-            let typ = self.globals.borrow().get(name).expect("global").get_type();
+            let typ = self.globals.borrow()[name].get_type();
             let global = self.context.new_global(None, GlobalKind::Imported, typ, name);
             if is_tls {
                 global.set_tls_model(self.tls_model);
@@ -103,11 +103,13 @@
 /// update the declaration and return existing Value instead.
 fn declare_raw_fn<'gcc>(cx: &CodegenCx<'gcc, '_>, name: &str, _callconv: () /*llvm::CallConv*/, return_type: Type<'gcc>, param_types: &[Type<'gcc>], variadic: bool) -> Function<'gcc> {
     if name.starts_with("llvm.") {
-        return llvm::intrinsic(name, cx);
+        let intrinsic = llvm::intrinsic(name, cx);
+        cx.intrinsics.borrow_mut().insert(name.to_string(), intrinsic);
+        return intrinsic;
     }
     let func =
         if cx.functions.borrow().contains_key(name) {
-            *cx.functions.borrow().get(name).expect("function")
+            cx.functions.borrow()[name]
         }
         else {
             let params: Vec<_> = param_types.into_iter().enumerate()
diff --git a/compiler/rustc_codegen_gcc/src/int.rs b/compiler/rustc_codegen_gcc/src/int.rs
index c3ed71f..0c5dab0 100644
--- a/compiler/rustc_codegen_gcc/src/int.rs
+++ b/compiler/rustc_codegen_gcc/src/int.rs
@@ -153,8 +153,15 @@
         let a_type = a.get_type();
         let b_type = b.get_type();
         if self.is_native_int_type_or_bool(a_type) && self.is_native_int_type_or_bool(b_type) {
-            if a.get_type() != b.get_type() {
-                b = self.context.new_cast(None, b, a.get_type());
+            if a_type != b_type {
+                if a_type.is_vector() {
+                    // Vector types need to be bitcast.
+                    // TODO(antoyo): perhaps use __builtin_convertvector for vector casting.
+                    b = self.context.new_bitcast(None, b, a.get_type());
+                }
+                else {
+                    b = self.context.new_cast(None, b, a.get_type());
+                }
             }
             self.context.new_binary_op(None, operation, a_type, a, b)
         }
@@ -593,7 +600,10 @@
         let b_type = b.get_type();
         let a_native = self.is_native_int_type_or_bool(a_type);
         let b_native = self.is_native_int_type_or_bool(b_type);
-        if a_native && b_native {
+        if a_type.is_vector() && b_type.is_vector() {
+            self.context.new_binary_op(None, operation, a_type, a, b)
+        }
+        else if a_native && b_native {
             if a_type != b_type {
                 b = self.context.new_cast(None, b, a_type);
             }
@@ -639,6 +649,8 @@
         else {
             // Since u128 and i128 are the only types that can be unsupported, we know the type of
             // value and the destination type have the same size, so a bitcast is fine.
+
+            // TODO(antoyo): perhaps use __builtin_convertvector for vector casting.
             self.context.new_bitcast(None, value, dest_typ)
         }
     }
diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/archs.rs b/compiler/rustc_codegen_gcc/src/intrinsic/archs.rs
new file mode 100644
index 0000000..fb6c38f
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/src/intrinsic/archs.rs
@@ -0,0 +1,5722 @@
+// File generated by `rustc_codegen_gcc/tools/generate_intrinsics.py`
+// DO NOT EDIT IT!
+match name {
+    // AMDGPU
+    "llvm.AMDGPU.div.fixup.f32" => "__builtin_amdgpu_div_fixup",
+    "llvm.AMDGPU.div.fixup.f64" => "__builtin_amdgpu_div_fixup",
+    "llvm.AMDGPU.div.fixup.v2f64" => "__builtin_amdgpu_div_fixup",
+    "llvm.AMDGPU.div.fixup.v4f32" => "__builtin_amdgpu_div_fixup",
+    "llvm.AMDGPU.div.fmas.f32" => "__builtin_amdgpu_div_fmas",
+    "llvm.AMDGPU.div.fmas.f64" => "__builtin_amdgpu_div_fmas",
+    "llvm.AMDGPU.div.fmas.v2f64" => "__builtin_amdgpu_div_fmas",
+    "llvm.AMDGPU.div.fmas.v4f32" => "__builtin_amdgpu_div_fmas",
+    "llvm.AMDGPU.ldexp.f32" => "__builtin_amdgpu_ldexp",
+    "llvm.AMDGPU.ldexp.f64" => "__builtin_amdgpu_ldexp",
+    "llvm.AMDGPU.ldexp.v2f64" => "__builtin_amdgpu_ldexp",
+    "llvm.AMDGPU.ldexp.v4f32" => "__builtin_amdgpu_ldexp",
+    "llvm.AMDGPU.rcp.f32" => "__builtin_amdgpu_rcp",
+    "llvm.AMDGPU.rcp.f64" => "__builtin_amdgpu_rcp",
+    "llvm.AMDGPU.rcp.v2f64" => "__builtin_amdgpu_rcp",
+    "llvm.AMDGPU.rcp.v4f32" => "__builtin_amdgpu_rcp",
+    "llvm.AMDGPU.rsq.clamped.f32" => "__builtin_amdgpu_rsq_clamped",
+    "llvm.AMDGPU.rsq.clamped.f64" => "__builtin_amdgpu_rsq_clamped",
+    "llvm.AMDGPU.rsq.clamped.v2f64" => "__builtin_amdgpu_rsq_clamped",
+    "llvm.AMDGPU.rsq.clamped.v4f32" => "__builtin_amdgpu_rsq_clamped",
+    "llvm.AMDGPU.rsq.f32" => "__builtin_amdgpu_rsq",
+    "llvm.AMDGPU.rsq.f64" => "__builtin_amdgpu_rsq",
+    "llvm.AMDGPU.rsq.v2f64" => "__builtin_amdgpu_rsq",
+    "llvm.AMDGPU.rsq.v4f32" => "__builtin_amdgpu_rsq",
+    "llvm.AMDGPU.trig.preop.f32" => "__builtin_amdgpu_trig_preop",
+    "llvm.AMDGPU.trig.preop.f64" => "__builtin_amdgpu_trig_preop",
+    "llvm.AMDGPU.trig.preop.v2f64" => "__builtin_amdgpu_trig_preop",
+    "llvm.AMDGPU.trig.preop.v4f32" => "__builtin_amdgpu_trig_preop",
+    // aarch64
+    "llvm.aarch64.dmb" => "__builtin_arm_dmb",
+    "llvm.aarch64.dsb" => "__builtin_arm_dsb",
+    "llvm.aarch64.isb" => "__builtin_arm_isb",
+    "llvm.aarch64.sve.aesd" => "__builtin_sve_svaesd_u8",
+    "llvm.aarch64.sve.aese" => "__builtin_sve_svaese_u8",
+    "llvm.aarch64.sve.aesimc" => "__builtin_sve_svaesimc_u8",
+    "llvm.aarch64.sve.aesmc" => "__builtin_sve_svaesmc_u8",
+    "llvm.aarch64.sve.rax1" => "__builtin_sve_svrax1_u64",
+    "llvm.aarch64.sve.rdffr" => "__builtin_sve_svrdffr",
+    "llvm.aarch64.sve.rdffr.z" => "__builtin_sve_svrdffr_z",
+    "llvm.aarch64.sve.setffr" => "__builtin_sve_svsetffr",
+    "llvm.aarch64.sve.sm4e" => "__builtin_sve_svsm4e_u32",
+    "llvm.aarch64.sve.sm4ekey" => "__builtin_sve_svsm4ekey_u32",
+    "llvm.aarch64.sve.wrffr" => "__builtin_sve_svwrffr",
+    "llvm.aarch64.tcancel" => "__builtin_arm_tcancel",
+    "llvm.aarch64.tcommit" => "__builtin_arm_tcommit",
+    "llvm.aarch64.tstart" => "__builtin_arm_tstart",
+    "llvm.aarch64.ttest" => "__builtin_arm_ttest",
+    // amdgcn
+    "llvm.amdgcn.alignbyte" => "__builtin_amdgcn_alignbyte",
+    "llvm.amdgcn.buffer.wbinvl1" => "__builtin_amdgcn_buffer_wbinvl1",
+    "llvm.amdgcn.buffer.wbinvl1.sc" => "__builtin_amdgcn_buffer_wbinvl1_sc",
+    "llvm.amdgcn.buffer.wbinvl1.vol" => "__builtin_amdgcn_buffer_wbinvl1_vol",
+    "llvm.amdgcn.cubeid" => "__builtin_amdgcn_cubeid",
+    "llvm.amdgcn.cubema" => "__builtin_amdgcn_cubema",
+    "llvm.amdgcn.cubesc" => "__builtin_amdgcn_cubesc",
+    "llvm.amdgcn.cubetc" => "__builtin_amdgcn_cubetc",
+    "llvm.amdgcn.cvt.pk.i16" => "__builtin_amdgcn_cvt_pk_i16",
+    "llvm.amdgcn.cvt.pk.u16" => "__builtin_amdgcn_cvt_pk_u16",
+    "llvm.amdgcn.cvt.pk.u8.f32" => "__builtin_amdgcn_cvt_pk_u8_f32",
+    "llvm.amdgcn.cvt.pknorm.i16" => "__builtin_amdgcn_cvt_pknorm_i16",
+    "llvm.amdgcn.cvt.pknorm.u16" => "__builtin_amdgcn_cvt_pknorm_u16",
+    "llvm.amdgcn.cvt.pkrtz" => "__builtin_amdgcn_cvt_pkrtz",
+    "llvm.amdgcn.dispatch.id" => "__builtin_amdgcn_dispatch_id",
+    "llvm.amdgcn.ds.bpermute" => "__builtin_amdgcn_ds_bpermute",
+    "llvm.amdgcn.ds.fadd.v2bf16" => "__builtin_amdgcn_ds_atomic_fadd_v2bf16",
+    "llvm.amdgcn.ds.gws.barrier" => "__builtin_amdgcn_ds_gws_barrier",
+    "llvm.amdgcn.ds.gws.init" => "__builtin_amdgcn_ds_gws_init",
+    "llvm.amdgcn.ds.gws.sema.br" => "__builtin_amdgcn_ds_gws_sema_br",
+    "llvm.amdgcn.ds.gws.sema.p" => "__builtin_amdgcn_ds_gws_sema_p",
+    "llvm.amdgcn.ds.gws.sema.release.all" => "__builtin_amdgcn_ds_gws_sema_release_all",
+    "llvm.amdgcn.ds.gws.sema.v" => "__builtin_amdgcn_ds_gws_sema_v",
+    "llvm.amdgcn.ds.permute" => "__builtin_amdgcn_ds_permute",
+    "llvm.amdgcn.ds.swizzle" => "__builtin_amdgcn_ds_swizzle",
+    "llvm.amdgcn.endpgm" => "__builtin_amdgcn_endpgm",
+    "llvm.amdgcn.fdot2" => "__builtin_amdgcn_fdot2",
+    "llvm.amdgcn.fmed3" => "__builtin_amdgcn_fmed3",
+    "llvm.amdgcn.fmul.legacy" => "__builtin_amdgcn_fmul_legacy",
+    "llvm.amdgcn.groupstaticsize" => "__builtin_amdgcn_groupstaticsize",
+    "llvm.amdgcn.implicit.buffer.ptr" => "__builtin_amdgcn_implicit_buffer_ptr",
+    "llvm.amdgcn.implicitarg.ptr" => "__builtin_amdgcn_implicitarg_ptr",
+    "llvm.amdgcn.interp.mov" => "__builtin_amdgcn_interp_mov",
+    "llvm.amdgcn.interp.p1" => "__builtin_amdgcn_interp_p1",
+    "llvm.amdgcn.interp.p1.f16" => "__builtin_amdgcn_interp_p1_f16",
+    "llvm.amdgcn.interp.p2" => "__builtin_amdgcn_interp_p2",
+    "llvm.amdgcn.interp.p2.f16" => "__builtin_amdgcn_interp_p2_f16",
+    "llvm.amdgcn.is.private" => "__builtin_amdgcn_is_private",
+    "llvm.amdgcn.is.shared" => "__builtin_amdgcn_is_shared",
+    "llvm.amdgcn.kernarg.segment.ptr" => "__builtin_amdgcn_kernarg_segment_ptr",
+    "llvm.amdgcn.lerp" => "__builtin_amdgcn_lerp",
+    "llvm.amdgcn.mbcnt.hi" => "__builtin_amdgcn_mbcnt_hi",
+    "llvm.amdgcn.mbcnt.lo" => "__builtin_amdgcn_mbcnt_lo",
+    "llvm.amdgcn.mqsad.pk.u16.u8" => "__builtin_amdgcn_mqsad_pk_u16_u8",
+    "llvm.amdgcn.mqsad.u32.u8" => "__builtin_amdgcn_mqsad_u32_u8",
+    "llvm.amdgcn.msad.u8" => "__builtin_amdgcn_msad_u8",
+    "llvm.amdgcn.perm" => "__builtin_amdgcn_perm",
+    "llvm.amdgcn.permlane16" => "__builtin_amdgcn_permlane16",
+    "llvm.amdgcn.permlanex16" => "__builtin_amdgcn_permlanex16",
+    "llvm.amdgcn.qsad.pk.u16.u8" => "__builtin_amdgcn_qsad_pk_u16_u8",
+    "llvm.amdgcn.queue.ptr" => "__builtin_amdgcn_queue_ptr",
+    "llvm.amdgcn.rcp.legacy" => "__builtin_amdgcn_rcp_legacy",
+    "llvm.amdgcn.readfirstlane" => "__builtin_amdgcn_readfirstlane",
+    "llvm.amdgcn.readlane" => "__builtin_amdgcn_readlane",
+    "llvm.amdgcn.rsq.legacy" => "__builtin_amdgcn_rsq_legacy",
+    "llvm.amdgcn.s.barrier" => "__builtin_amdgcn_s_barrier",
+    "llvm.amdgcn.s.dcache.inv" => "__builtin_amdgcn_s_dcache_inv",
+    "llvm.amdgcn.s.dcache.inv.vol" => "__builtin_amdgcn_s_dcache_inv_vol",
+    "llvm.amdgcn.s.dcache.wb" => "__builtin_amdgcn_s_dcache_wb",
+    "llvm.amdgcn.s.dcache.wb.vol" => "__builtin_amdgcn_s_dcache_wb_vol",
+    "llvm.amdgcn.s.decperflevel" => "__builtin_amdgcn_s_decperflevel",
+    "llvm.amdgcn.s.get.waveid.in.workgroup" => "__builtin_amdgcn_s_get_waveid_in_workgroup",
+    "llvm.amdgcn.s.getpc" => "__builtin_amdgcn_s_getpc",
+    "llvm.amdgcn.s.getreg" => "__builtin_amdgcn_s_getreg",
+    "llvm.amdgcn.s.incperflevel" => "__builtin_amdgcn_s_incperflevel",
+    "llvm.amdgcn.s.memrealtime" => "__builtin_amdgcn_s_memrealtime",
+    "llvm.amdgcn.s.memtime" => "__builtin_amdgcn_s_memtime",
+    "llvm.amdgcn.s.sendmsg" => "__builtin_amdgcn_s_sendmsg",
+    "llvm.amdgcn.s.sendmsghalt" => "__builtin_amdgcn_s_sendmsghalt",
+    "llvm.amdgcn.s.setprio" => "__builtin_amdgcn_s_setprio",
+    "llvm.amdgcn.s.setreg" => "__builtin_amdgcn_s_setreg",
+    "llvm.amdgcn.s.sleep" => "__builtin_amdgcn_s_sleep",
+    "llvm.amdgcn.s.waitcnt" => "__builtin_amdgcn_s_waitcnt",
+    "llvm.amdgcn.sad.hi.u8" => "__builtin_amdgcn_sad_hi_u8",
+    "llvm.amdgcn.sad.u16" => "__builtin_amdgcn_sad_u16",
+    "llvm.amdgcn.sad.u8" => "__builtin_amdgcn_sad_u8",
+    "llvm.amdgcn.sched.barrier" => "__builtin_amdgcn_sched_barrier",
+    "llvm.amdgcn.sdot2" => "__builtin_amdgcn_sdot2",
+    "llvm.amdgcn.sdot4" => "__builtin_amdgcn_sdot4",
+    "llvm.amdgcn.sdot8" => "__builtin_amdgcn_sdot8",
+    "llvm.amdgcn.udot2" => "__builtin_amdgcn_udot2",
+    "llvm.amdgcn.udot4" => "__builtin_amdgcn_udot4",
+    "llvm.amdgcn.udot8" => "__builtin_amdgcn_udot8",
+    "llvm.amdgcn.wave.barrier" => "__builtin_amdgcn_wave_barrier",
+    "llvm.amdgcn.wavefrontsize" => "__builtin_amdgcn_wavefrontsize",
+    "llvm.amdgcn.writelane" => "__builtin_amdgcn_writelane",
+    // arm
+    "llvm.arm.cdp" => "__builtin_arm_cdp",
+    "llvm.arm.cdp2" => "__builtin_arm_cdp2",
+    "llvm.arm.cmse.tt" => "__builtin_arm_cmse_TT",
+    "llvm.arm.cmse.tta" => "__builtin_arm_cmse_TTA",
+    "llvm.arm.cmse.ttat" => "__builtin_arm_cmse_TTAT",
+    "llvm.arm.cmse.ttt" => "__builtin_arm_cmse_TTT",
+    "llvm.arm.dmb" => "__builtin_arm_dmb",
+    "llvm.arm.dsb" => "__builtin_arm_dsb",
+    "llvm.arm.get.fpscr" => "__builtin_arm_get_fpscr",
+    "llvm.arm.isb" => "__builtin_arm_isb",
+    "llvm.arm.ldc" => "__builtin_arm_ldc",
+    "llvm.arm.ldc2" => "__builtin_arm_ldc2",
+    "llvm.arm.ldc2l" => "__builtin_arm_ldc2l",
+    "llvm.arm.ldcl" => "__builtin_arm_ldcl",
+    "llvm.arm.mcr" => "__builtin_arm_mcr",
+    "llvm.arm.mcr2" => "__builtin_arm_mcr2",
+    "llvm.arm.mcrr" => "__builtin_arm_mcrr",
+    "llvm.arm.mcrr2" => "__builtin_arm_mcrr2",
+    "llvm.arm.mrc" => "__builtin_arm_mrc",
+    "llvm.arm.mrc2" => "__builtin_arm_mrc2",
+    "llvm.arm.qadd" => "__builtin_arm_qadd",
+    "llvm.arm.qadd16" => "__builtin_arm_qadd16",
+    "llvm.arm.qadd8" => "__builtin_arm_qadd8",
+    "llvm.arm.qasx" => "__builtin_arm_qasx",
+    "llvm.arm.qsax" => "__builtin_arm_qsax",
+    "llvm.arm.qsub" => "__builtin_arm_qsub",
+    "llvm.arm.qsub16" => "__builtin_arm_qsub16",
+    "llvm.arm.qsub8" => "__builtin_arm_qsub8",
+    "llvm.arm.sadd16" => "__builtin_arm_sadd16",
+    "llvm.arm.sadd8" => "__builtin_arm_sadd8",
+    "llvm.arm.sasx" => "__builtin_arm_sasx",
+    "llvm.arm.sel" => "__builtin_arm_sel",
+    "llvm.arm.set.fpscr" => "__builtin_arm_set_fpscr",
+    "llvm.arm.shadd16" => "__builtin_arm_shadd16",
+    "llvm.arm.shadd8" => "__builtin_arm_shadd8",
+    "llvm.arm.shasx" => "__builtin_arm_shasx",
+    "llvm.arm.shsax" => "__builtin_arm_shsax",
+    "llvm.arm.shsub16" => "__builtin_arm_shsub16",
+    "llvm.arm.shsub8" => "__builtin_arm_shsub8",
+    "llvm.arm.smlabb" => "__builtin_arm_smlabb",
+    "llvm.arm.smlabt" => "__builtin_arm_smlabt",
+    "llvm.arm.smlad" => "__builtin_arm_smlad",
+    "llvm.arm.smladx" => "__builtin_arm_smladx",
+    "llvm.arm.smlald" => "__builtin_arm_smlald",
+    "llvm.arm.smlaldx" => "__builtin_arm_smlaldx",
+    "llvm.arm.smlatb" => "__builtin_arm_smlatb",
+    "llvm.arm.smlatt" => "__builtin_arm_smlatt",
+    "llvm.arm.smlawb" => "__builtin_arm_smlawb",
+    "llvm.arm.smlawt" => "__builtin_arm_smlawt",
+    "llvm.arm.smlsd" => "__builtin_arm_smlsd",
+    "llvm.arm.smlsdx" => "__builtin_arm_smlsdx",
+    "llvm.arm.smlsld" => "__builtin_arm_smlsld",
+    "llvm.arm.smlsldx" => "__builtin_arm_smlsldx",
+    "llvm.arm.smuad" => "__builtin_arm_smuad",
+    "llvm.arm.smuadx" => "__builtin_arm_smuadx",
+    "llvm.arm.smulbb" => "__builtin_arm_smulbb",
+    "llvm.arm.smulbt" => "__builtin_arm_smulbt",
+    "llvm.arm.smultb" => "__builtin_arm_smultb",
+    "llvm.arm.smultt" => "__builtin_arm_smultt",
+    "llvm.arm.smulwb" => "__builtin_arm_smulwb",
+    "llvm.arm.smulwt" => "__builtin_arm_smulwt",
+    "llvm.arm.smusd" => "__builtin_arm_smusd",
+    "llvm.arm.smusdx" => "__builtin_arm_smusdx",
+    "llvm.arm.ssat" => "__builtin_arm_ssat",
+    "llvm.arm.ssat16" => "__builtin_arm_ssat16",
+    "llvm.arm.ssax" => "__builtin_arm_ssax",
+    "llvm.arm.ssub16" => "__builtin_arm_ssub16",
+    "llvm.arm.ssub8" => "__builtin_arm_ssub8",
+    "llvm.arm.stc" => "__builtin_arm_stc",
+    "llvm.arm.stc2" => "__builtin_arm_stc2",
+    "llvm.arm.stc2l" => "__builtin_arm_stc2l",
+    "llvm.arm.stcl" => "__builtin_arm_stcl",
+    "llvm.arm.sxtab16" => "__builtin_arm_sxtab16",
+    "llvm.arm.sxtb16" => "__builtin_arm_sxtb16",
+    "llvm.arm.thread.pointer" => "__builtin_thread_pointer",
+    "llvm.arm.uadd16" => "__builtin_arm_uadd16",
+    "llvm.arm.uadd8" => "__builtin_arm_uadd8",
+    "llvm.arm.uasx" => "__builtin_arm_uasx",
+    "llvm.arm.uhadd16" => "__builtin_arm_uhadd16",
+    "llvm.arm.uhadd8" => "__builtin_arm_uhadd8",
+    "llvm.arm.uhasx" => "__builtin_arm_uhasx",
+    "llvm.arm.uhsax" => "__builtin_arm_uhsax",
+    "llvm.arm.uhsub16" => "__builtin_arm_uhsub16",
+    "llvm.arm.uhsub8" => "__builtin_arm_uhsub8",
+    "llvm.arm.uqadd16" => "__builtin_arm_uqadd16",
+    "llvm.arm.uqadd8" => "__builtin_arm_uqadd8",
+    "llvm.arm.uqasx" => "__builtin_arm_uqasx",
+    "llvm.arm.uqsax" => "__builtin_arm_uqsax",
+    "llvm.arm.uqsub16" => "__builtin_arm_uqsub16",
+    "llvm.arm.uqsub8" => "__builtin_arm_uqsub8",
+    "llvm.arm.usad8" => "__builtin_arm_usad8",
+    "llvm.arm.usada8" => "__builtin_arm_usada8",
+    "llvm.arm.usat" => "__builtin_arm_usat",
+    "llvm.arm.usat16" => "__builtin_arm_usat16",
+    "llvm.arm.usax" => "__builtin_arm_usax",
+    "llvm.arm.usub16" => "__builtin_arm_usub16",
+    "llvm.arm.usub8" => "__builtin_arm_usub8",
+    "llvm.arm.uxtab16" => "__builtin_arm_uxtab16",
+    "llvm.arm.uxtb16" => "__builtin_arm_uxtb16",
+    // bpf
+    "llvm.bpf.btf.type.id" => "__builtin_bpf_btf_type_id",
+    "llvm.bpf.compare" => "__builtin_bpf_compare",
+    "llvm.bpf.load.byte" => "__builtin_bpf_load_byte",
+    "llvm.bpf.load.half" => "__builtin_bpf_load_half",
+    "llvm.bpf.load.word" => "__builtin_bpf_load_word",
+    "llvm.bpf.passthrough" => "__builtin_bpf_passthrough",
+    "llvm.bpf.preserve.enum.value" => "__builtin_bpf_preserve_enum_value",
+    "llvm.bpf.preserve.field.info" => "__builtin_bpf_preserve_field_info",
+    "llvm.bpf.preserve.type.info" => "__builtin_bpf_preserve_type_info",
+    "llvm.bpf.pseudo" => "__builtin_bpf_pseudo",
+    // cuda
+    "llvm.cuda.syncthreads" => "__syncthreads",
+    // hexagon
+    "llvm.hexagon.A2.abs" => "__builtin_HEXAGON_A2_abs",
+    "llvm.hexagon.A2.absp" => "__builtin_HEXAGON_A2_absp",
+    "llvm.hexagon.A2.abssat" => "__builtin_HEXAGON_A2_abssat",
+    "llvm.hexagon.A2.add" => "__builtin_HEXAGON_A2_add",
+    "llvm.hexagon.A2.addh.h16.hh" => "__builtin_HEXAGON_A2_addh_h16_hh",
+    "llvm.hexagon.A2.addh.h16.hl" => "__builtin_HEXAGON_A2_addh_h16_hl",
+    "llvm.hexagon.A2.addh.h16.lh" => "__builtin_HEXAGON_A2_addh_h16_lh",
+    "llvm.hexagon.A2.addh.h16.ll" => "__builtin_HEXAGON_A2_addh_h16_ll",
+    "llvm.hexagon.A2.addh.h16.sat.hh" => "__builtin_HEXAGON_A2_addh_h16_sat_hh",
+    "llvm.hexagon.A2.addh.h16.sat.hl" => "__builtin_HEXAGON_A2_addh_h16_sat_hl",
+    "llvm.hexagon.A2.addh.h16.sat.lh" => "__builtin_HEXAGON_A2_addh_h16_sat_lh",
+    "llvm.hexagon.A2.addh.h16.sat.ll" => "__builtin_HEXAGON_A2_addh_h16_sat_ll",
+    "llvm.hexagon.A2.addh.l16.hl" => "__builtin_HEXAGON_A2_addh_l16_hl",
+    "llvm.hexagon.A2.addh.l16.ll" => "__builtin_HEXAGON_A2_addh_l16_ll",
+    "llvm.hexagon.A2.addh.l16.sat.hl" => "__builtin_HEXAGON_A2_addh_l16_sat_hl",
+    "llvm.hexagon.A2.addh.l16.sat.ll" => "__builtin_HEXAGON_A2_addh_l16_sat_ll",
+    "llvm.hexagon.A2.addi" => "__builtin_HEXAGON_A2_addi",
+    "llvm.hexagon.A2.addp" => "__builtin_HEXAGON_A2_addp",
+    "llvm.hexagon.A2.addpsat" => "__builtin_HEXAGON_A2_addpsat",
+    "llvm.hexagon.A2.addsat" => "__builtin_HEXAGON_A2_addsat",
+    "llvm.hexagon.A2.addsp" => "__builtin_HEXAGON_A2_addsp",
+    "llvm.hexagon.A2.and" => "__builtin_HEXAGON_A2_and",
+    "llvm.hexagon.A2.andir" => "__builtin_HEXAGON_A2_andir",
+    "llvm.hexagon.A2.andp" => "__builtin_HEXAGON_A2_andp",
+    "llvm.hexagon.A2.aslh" => "__builtin_HEXAGON_A2_aslh",
+    "llvm.hexagon.A2.asrh" => "__builtin_HEXAGON_A2_asrh",
+    "llvm.hexagon.A2.combine.hh" => "__builtin_HEXAGON_A2_combine_hh",
+    "llvm.hexagon.A2.combine.hl" => "__builtin_HEXAGON_A2_combine_hl",
+    "llvm.hexagon.A2.combine.lh" => "__builtin_HEXAGON_A2_combine_lh",
+    "llvm.hexagon.A2.combine.ll" => "__builtin_HEXAGON_A2_combine_ll",
+    "llvm.hexagon.A2.combineii" => "__builtin_HEXAGON_A2_combineii",
+    "llvm.hexagon.A2.combinew" => "__builtin_HEXAGON_A2_combinew",
+    "llvm.hexagon.A2.max" => "__builtin_HEXAGON_A2_max",
+    "llvm.hexagon.A2.maxp" => "__builtin_HEXAGON_A2_maxp",
+    "llvm.hexagon.A2.maxu" => "__builtin_HEXAGON_A2_maxu",
+    "llvm.hexagon.A2.maxup" => "__builtin_HEXAGON_A2_maxup",
+    "llvm.hexagon.A2.min" => "__builtin_HEXAGON_A2_min",
+    "llvm.hexagon.A2.minp" => "__builtin_HEXAGON_A2_minp",
+    "llvm.hexagon.A2.minu" => "__builtin_HEXAGON_A2_minu",
+    "llvm.hexagon.A2.minup" => "__builtin_HEXAGON_A2_minup",
+    "llvm.hexagon.A2.neg" => "__builtin_HEXAGON_A2_neg",
+    "llvm.hexagon.A2.negp" => "__builtin_HEXAGON_A2_negp",
+    "llvm.hexagon.A2.negsat" => "__builtin_HEXAGON_A2_negsat",
+    "llvm.hexagon.A2.not" => "__builtin_HEXAGON_A2_not",
+    "llvm.hexagon.A2.notp" => "__builtin_HEXAGON_A2_notp",
+    "llvm.hexagon.A2.or" => "__builtin_HEXAGON_A2_or",
+    "llvm.hexagon.A2.orir" => "__builtin_HEXAGON_A2_orir",
+    "llvm.hexagon.A2.orp" => "__builtin_HEXAGON_A2_orp",
+    "llvm.hexagon.A2.roundsat" => "__builtin_HEXAGON_A2_roundsat",
+    "llvm.hexagon.A2.sat" => "__builtin_HEXAGON_A2_sat",
+    "llvm.hexagon.A2.satb" => "__builtin_HEXAGON_A2_satb",
+    "llvm.hexagon.A2.sath" => "__builtin_HEXAGON_A2_sath",
+    "llvm.hexagon.A2.satub" => "__builtin_HEXAGON_A2_satub",
+    "llvm.hexagon.A2.satuh" => "__builtin_HEXAGON_A2_satuh",
+    "llvm.hexagon.A2.sub" => "__builtin_HEXAGON_A2_sub",
+    "llvm.hexagon.A2.subh.h16.hh" => "__builtin_HEXAGON_A2_subh_h16_hh",
+    "llvm.hexagon.A2.subh.h16.hl" => "__builtin_HEXAGON_A2_subh_h16_hl",
+    "llvm.hexagon.A2.subh.h16.lh" => "__builtin_HEXAGON_A2_subh_h16_lh",
+    "llvm.hexagon.A2.subh.h16.ll" => "__builtin_HEXAGON_A2_subh_h16_ll",
+    "llvm.hexagon.A2.subh.h16.sat.hh" => "__builtin_HEXAGON_A2_subh_h16_sat_hh",
+    "llvm.hexagon.A2.subh.h16.sat.hl" => "__builtin_HEXAGON_A2_subh_h16_sat_hl",
+    "llvm.hexagon.A2.subh.h16.sat.lh" => "__builtin_HEXAGON_A2_subh_h16_sat_lh",
+    "llvm.hexagon.A2.subh.h16.sat.ll" => "__builtin_HEXAGON_A2_subh_h16_sat_ll",
+    "llvm.hexagon.A2.subh.l16.hl" => "__builtin_HEXAGON_A2_subh_l16_hl",
+    "llvm.hexagon.A2.subh.l16.ll" => "__builtin_HEXAGON_A2_subh_l16_ll",
+    "llvm.hexagon.A2.subh.l16.sat.hl" => "__builtin_HEXAGON_A2_subh_l16_sat_hl",
+    "llvm.hexagon.A2.subh.l16.sat.ll" => "__builtin_HEXAGON_A2_subh_l16_sat_ll",
+    "llvm.hexagon.A2.subp" => "__builtin_HEXAGON_A2_subp",
+    "llvm.hexagon.A2.subri" => "__builtin_HEXAGON_A2_subri",
+    "llvm.hexagon.A2.subsat" => "__builtin_HEXAGON_A2_subsat",
+    "llvm.hexagon.A2.svaddh" => "__builtin_HEXAGON_A2_svaddh",
+    "llvm.hexagon.A2.svaddhs" => "__builtin_HEXAGON_A2_svaddhs",
+    "llvm.hexagon.A2.svadduhs" => "__builtin_HEXAGON_A2_svadduhs",
+    "llvm.hexagon.A2.svavgh" => "__builtin_HEXAGON_A2_svavgh",
+    "llvm.hexagon.A2.svavghs" => "__builtin_HEXAGON_A2_svavghs",
+    "llvm.hexagon.A2.svnavgh" => "__builtin_HEXAGON_A2_svnavgh",
+    "llvm.hexagon.A2.svsubh" => "__builtin_HEXAGON_A2_svsubh",
+    "llvm.hexagon.A2.svsubhs" => "__builtin_HEXAGON_A2_svsubhs",
+    "llvm.hexagon.A2.svsubuhs" => "__builtin_HEXAGON_A2_svsubuhs",
+    "llvm.hexagon.A2.swiz" => "__builtin_HEXAGON_A2_swiz",
+    "llvm.hexagon.A2.sxtb" => "__builtin_HEXAGON_A2_sxtb",
+    "llvm.hexagon.A2.sxth" => "__builtin_HEXAGON_A2_sxth",
+    "llvm.hexagon.A2.sxtw" => "__builtin_HEXAGON_A2_sxtw",
+    "llvm.hexagon.A2.tfr" => "__builtin_HEXAGON_A2_tfr",
+    "llvm.hexagon.A2.tfrih" => "__builtin_HEXAGON_A2_tfrih",
+    "llvm.hexagon.A2.tfril" => "__builtin_HEXAGON_A2_tfril",
+    "llvm.hexagon.A2.tfrp" => "__builtin_HEXAGON_A2_tfrp",
+    "llvm.hexagon.A2.tfrpi" => "__builtin_HEXAGON_A2_tfrpi",
+    "llvm.hexagon.A2.tfrsi" => "__builtin_HEXAGON_A2_tfrsi",
+    "llvm.hexagon.A2.vabsh" => "__builtin_HEXAGON_A2_vabsh",
+    "llvm.hexagon.A2.vabshsat" => "__builtin_HEXAGON_A2_vabshsat",
+    "llvm.hexagon.A2.vabsw" => "__builtin_HEXAGON_A2_vabsw",
+    "llvm.hexagon.A2.vabswsat" => "__builtin_HEXAGON_A2_vabswsat",
+    "llvm.hexagon.A2.vaddb.map" => "__builtin_HEXAGON_A2_vaddb_map",
+    "llvm.hexagon.A2.vaddh" => "__builtin_HEXAGON_A2_vaddh",
+    "llvm.hexagon.A2.vaddhs" => "__builtin_HEXAGON_A2_vaddhs",
+    "llvm.hexagon.A2.vaddub" => "__builtin_HEXAGON_A2_vaddub",
+    "llvm.hexagon.A2.vaddubs" => "__builtin_HEXAGON_A2_vaddubs",
+    "llvm.hexagon.A2.vadduhs" => "__builtin_HEXAGON_A2_vadduhs",
+    "llvm.hexagon.A2.vaddw" => "__builtin_HEXAGON_A2_vaddw",
+    "llvm.hexagon.A2.vaddws" => "__builtin_HEXAGON_A2_vaddws",
+    "llvm.hexagon.A2.vavgh" => "__builtin_HEXAGON_A2_vavgh",
+    "llvm.hexagon.A2.vavghcr" => "__builtin_HEXAGON_A2_vavghcr",
+    "llvm.hexagon.A2.vavghr" => "__builtin_HEXAGON_A2_vavghr",
+    "llvm.hexagon.A2.vavgub" => "__builtin_HEXAGON_A2_vavgub",
+    "llvm.hexagon.A2.vavgubr" => "__builtin_HEXAGON_A2_vavgubr",
+    "llvm.hexagon.A2.vavguh" => "__builtin_HEXAGON_A2_vavguh",
+    "llvm.hexagon.A2.vavguhr" => "__builtin_HEXAGON_A2_vavguhr",
+    "llvm.hexagon.A2.vavguw" => "__builtin_HEXAGON_A2_vavguw",
+    "llvm.hexagon.A2.vavguwr" => "__builtin_HEXAGON_A2_vavguwr",
+    "llvm.hexagon.A2.vavgw" => "__builtin_HEXAGON_A2_vavgw",
+    "llvm.hexagon.A2.vavgwcr" => "__builtin_HEXAGON_A2_vavgwcr",
+    "llvm.hexagon.A2.vavgwr" => "__builtin_HEXAGON_A2_vavgwr",
+    "llvm.hexagon.A2.vcmpbeq" => "__builtin_HEXAGON_A2_vcmpbeq",
+    "llvm.hexagon.A2.vcmpbgtu" => "__builtin_HEXAGON_A2_vcmpbgtu",
+    "llvm.hexagon.A2.vcmpheq" => "__builtin_HEXAGON_A2_vcmpheq",
+    "llvm.hexagon.A2.vcmphgt" => "__builtin_HEXAGON_A2_vcmphgt",
+    "llvm.hexagon.A2.vcmphgtu" => "__builtin_HEXAGON_A2_vcmphgtu",
+    "llvm.hexagon.A2.vcmpweq" => "__builtin_HEXAGON_A2_vcmpweq",
+    "llvm.hexagon.A2.vcmpwgt" => "__builtin_HEXAGON_A2_vcmpwgt",
+    "llvm.hexagon.A2.vcmpwgtu" => "__builtin_HEXAGON_A2_vcmpwgtu",
+    "llvm.hexagon.A2.vconj" => "__builtin_HEXAGON_A2_vconj",
+    "llvm.hexagon.A2.vmaxb" => "__builtin_HEXAGON_A2_vmaxb",
+    "llvm.hexagon.A2.vmaxh" => "__builtin_HEXAGON_A2_vmaxh",
+    "llvm.hexagon.A2.vmaxub" => "__builtin_HEXAGON_A2_vmaxub",
+    "llvm.hexagon.A2.vmaxuh" => "__builtin_HEXAGON_A2_vmaxuh",
+    "llvm.hexagon.A2.vmaxuw" => "__builtin_HEXAGON_A2_vmaxuw",
+    "llvm.hexagon.A2.vmaxw" => "__builtin_HEXAGON_A2_vmaxw",
+    "llvm.hexagon.A2.vminb" => "__builtin_HEXAGON_A2_vminb",
+    "llvm.hexagon.A2.vminh" => "__builtin_HEXAGON_A2_vminh",
+    "llvm.hexagon.A2.vminub" => "__builtin_HEXAGON_A2_vminub",
+    "llvm.hexagon.A2.vminuh" => "__builtin_HEXAGON_A2_vminuh",
+    "llvm.hexagon.A2.vminuw" => "__builtin_HEXAGON_A2_vminuw",
+    "llvm.hexagon.A2.vminw" => "__builtin_HEXAGON_A2_vminw",
+    "llvm.hexagon.A2.vnavgh" => "__builtin_HEXAGON_A2_vnavgh",
+    "llvm.hexagon.A2.vnavghcr" => "__builtin_HEXAGON_A2_vnavghcr",
+    "llvm.hexagon.A2.vnavghr" => "__builtin_HEXAGON_A2_vnavghr",
+    "llvm.hexagon.A2.vnavgw" => "__builtin_HEXAGON_A2_vnavgw",
+    "llvm.hexagon.A2.vnavgwcr" => "__builtin_HEXAGON_A2_vnavgwcr",
+    "llvm.hexagon.A2.vnavgwr" => "__builtin_HEXAGON_A2_vnavgwr",
+    "llvm.hexagon.A2.vraddub" => "__builtin_HEXAGON_A2_vraddub",
+    "llvm.hexagon.A2.vraddub.acc" => "__builtin_HEXAGON_A2_vraddub_acc",
+    "llvm.hexagon.A2.vrsadub" => "__builtin_HEXAGON_A2_vrsadub",
+    "llvm.hexagon.A2.vrsadub.acc" => "__builtin_HEXAGON_A2_vrsadub_acc",
+    "llvm.hexagon.A2.vsubb.map" => "__builtin_HEXAGON_A2_vsubb_map",
+    "llvm.hexagon.A2.vsubh" => "__builtin_HEXAGON_A2_vsubh",
+    "llvm.hexagon.A2.vsubhs" => "__builtin_HEXAGON_A2_vsubhs",
+    "llvm.hexagon.A2.vsubub" => "__builtin_HEXAGON_A2_vsubub",
+    "llvm.hexagon.A2.vsububs" => "__builtin_HEXAGON_A2_vsububs",
+    "llvm.hexagon.A2.vsubuhs" => "__builtin_HEXAGON_A2_vsubuhs",
+    "llvm.hexagon.A2.vsubw" => "__builtin_HEXAGON_A2_vsubw",
+    "llvm.hexagon.A2.vsubws" => "__builtin_HEXAGON_A2_vsubws",
+    "llvm.hexagon.A2.xor" => "__builtin_HEXAGON_A2_xor",
+    "llvm.hexagon.A2.xorp" => "__builtin_HEXAGON_A2_xorp",
+    "llvm.hexagon.A2.zxtb" => "__builtin_HEXAGON_A2_zxtb",
+    "llvm.hexagon.A2.zxth" => "__builtin_HEXAGON_A2_zxth",
+    "llvm.hexagon.A4.andn" => "__builtin_HEXAGON_A4_andn",
+    "llvm.hexagon.A4.andnp" => "__builtin_HEXAGON_A4_andnp",
+    "llvm.hexagon.A4.bitsplit" => "__builtin_HEXAGON_A4_bitsplit",
+    "llvm.hexagon.A4.bitspliti" => "__builtin_HEXAGON_A4_bitspliti",
+    "llvm.hexagon.A4.boundscheck" => "__builtin_HEXAGON_A4_boundscheck",
+    "llvm.hexagon.A4.cmpbeq" => "__builtin_HEXAGON_A4_cmpbeq",
+    "llvm.hexagon.A4.cmpbeqi" => "__builtin_HEXAGON_A4_cmpbeqi",
+    "llvm.hexagon.A4.cmpbgt" => "__builtin_HEXAGON_A4_cmpbgt",
+    "llvm.hexagon.A4.cmpbgti" => "__builtin_HEXAGON_A4_cmpbgti",
+    "llvm.hexagon.A4.cmpbgtu" => "__builtin_HEXAGON_A4_cmpbgtu",
+    "llvm.hexagon.A4.cmpbgtui" => "__builtin_HEXAGON_A4_cmpbgtui",
+    "llvm.hexagon.A4.cmpheq" => "__builtin_HEXAGON_A4_cmpheq",
+    "llvm.hexagon.A4.cmpheqi" => "__builtin_HEXAGON_A4_cmpheqi",
+    "llvm.hexagon.A4.cmphgt" => "__builtin_HEXAGON_A4_cmphgt",
+    "llvm.hexagon.A4.cmphgti" => "__builtin_HEXAGON_A4_cmphgti",
+    "llvm.hexagon.A4.cmphgtu" => "__builtin_HEXAGON_A4_cmphgtu",
+    "llvm.hexagon.A4.cmphgtui" => "__builtin_HEXAGON_A4_cmphgtui",
+    "llvm.hexagon.A4.combineir" => "__builtin_HEXAGON_A4_combineir",
+    "llvm.hexagon.A4.combineri" => "__builtin_HEXAGON_A4_combineri",
+    "llvm.hexagon.A4.cround.ri" => "__builtin_HEXAGON_A4_cround_ri",
+    "llvm.hexagon.A4.cround.rr" => "__builtin_HEXAGON_A4_cround_rr",
+    "llvm.hexagon.A4.modwrapu" => "__builtin_HEXAGON_A4_modwrapu",
+    "llvm.hexagon.A4.orn" => "__builtin_HEXAGON_A4_orn",
+    "llvm.hexagon.A4.ornp" => "__builtin_HEXAGON_A4_ornp",
+    "llvm.hexagon.A4.rcmpeq" => "__builtin_HEXAGON_A4_rcmpeq",
+    "llvm.hexagon.A4.rcmpeqi" => "__builtin_HEXAGON_A4_rcmpeqi",
+    "llvm.hexagon.A4.rcmpneq" => "__builtin_HEXAGON_A4_rcmpneq",
+    "llvm.hexagon.A4.rcmpneqi" => "__builtin_HEXAGON_A4_rcmpneqi",
+    "llvm.hexagon.A4.round.ri" => "__builtin_HEXAGON_A4_round_ri",
+    "llvm.hexagon.A4.round.ri.sat" => "__builtin_HEXAGON_A4_round_ri_sat",
+    "llvm.hexagon.A4.round.rr" => "__builtin_HEXAGON_A4_round_rr",
+    "llvm.hexagon.A4.round.rr.sat" => "__builtin_HEXAGON_A4_round_rr_sat",
+    "llvm.hexagon.A4.tlbmatch" => "__builtin_HEXAGON_A4_tlbmatch",
+    "llvm.hexagon.A4.vcmpbeq.any" => "__builtin_HEXAGON_A4_vcmpbeq_any",
+    "llvm.hexagon.A4.vcmpbeqi" => "__builtin_HEXAGON_A4_vcmpbeqi",
+    "llvm.hexagon.A4.vcmpbgt" => "__builtin_HEXAGON_A4_vcmpbgt",
+    "llvm.hexagon.A4.vcmpbgti" => "__builtin_HEXAGON_A4_vcmpbgti",
+    "llvm.hexagon.A4.vcmpbgtui" => "__builtin_HEXAGON_A4_vcmpbgtui",
+    "llvm.hexagon.A4.vcmpheqi" => "__builtin_HEXAGON_A4_vcmpheqi",
+    "llvm.hexagon.A4.vcmphgti" => "__builtin_HEXAGON_A4_vcmphgti",
+    "llvm.hexagon.A4.vcmphgtui" => "__builtin_HEXAGON_A4_vcmphgtui",
+    "llvm.hexagon.A4.vcmpweqi" => "__builtin_HEXAGON_A4_vcmpweqi",
+    "llvm.hexagon.A4.vcmpwgti" => "__builtin_HEXAGON_A4_vcmpwgti",
+    "llvm.hexagon.A4.vcmpwgtui" => "__builtin_HEXAGON_A4_vcmpwgtui",
+    "llvm.hexagon.A4.vrmaxh" => "__builtin_HEXAGON_A4_vrmaxh",
+    "llvm.hexagon.A4.vrmaxuh" => "__builtin_HEXAGON_A4_vrmaxuh",
+    "llvm.hexagon.A4.vrmaxuw" => "__builtin_HEXAGON_A4_vrmaxuw",
+    "llvm.hexagon.A4.vrmaxw" => "__builtin_HEXAGON_A4_vrmaxw",
+    "llvm.hexagon.A4.vrminh" => "__builtin_HEXAGON_A4_vrminh",
+    "llvm.hexagon.A4.vrminuh" => "__builtin_HEXAGON_A4_vrminuh",
+    "llvm.hexagon.A4.vrminuw" => "__builtin_HEXAGON_A4_vrminuw",
+    "llvm.hexagon.A4.vrminw" => "__builtin_HEXAGON_A4_vrminw",
+    "llvm.hexagon.A5.vaddhubs" => "__builtin_HEXAGON_A5_vaddhubs",
+    "llvm.hexagon.C2.all8" => "__builtin_HEXAGON_C2_all8",
+    "llvm.hexagon.C2.and" => "__builtin_HEXAGON_C2_and",
+    "llvm.hexagon.C2.andn" => "__builtin_HEXAGON_C2_andn",
+    "llvm.hexagon.C2.any8" => "__builtin_HEXAGON_C2_any8",
+    "llvm.hexagon.C2.bitsclr" => "__builtin_HEXAGON_C2_bitsclr",
+    "llvm.hexagon.C2.bitsclri" => "__builtin_HEXAGON_C2_bitsclri",
+    "llvm.hexagon.C2.bitsset" => "__builtin_HEXAGON_C2_bitsset",
+    "llvm.hexagon.C2.cmpeq" => "__builtin_HEXAGON_C2_cmpeq",
+    "llvm.hexagon.C2.cmpeqi" => "__builtin_HEXAGON_C2_cmpeqi",
+    "llvm.hexagon.C2.cmpeqp" => "__builtin_HEXAGON_C2_cmpeqp",
+    "llvm.hexagon.C2.cmpgei" => "__builtin_HEXAGON_C2_cmpgei",
+    "llvm.hexagon.C2.cmpgeui" => "__builtin_HEXAGON_C2_cmpgeui",
+    "llvm.hexagon.C2.cmpgt" => "__builtin_HEXAGON_C2_cmpgt",
+    "llvm.hexagon.C2.cmpgti" => "__builtin_HEXAGON_C2_cmpgti",
+    "llvm.hexagon.C2.cmpgtp" => "__builtin_HEXAGON_C2_cmpgtp",
+    "llvm.hexagon.C2.cmpgtu" => "__builtin_HEXAGON_C2_cmpgtu",
+    "llvm.hexagon.C2.cmpgtui" => "__builtin_HEXAGON_C2_cmpgtui",
+    "llvm.hexagon.C2.cmpgtup" => "__builtin_HEXAGON_C2_cmpgtup",
+    "llvm.hexagon.C2.cmplt" => "__builtin_HEXAGON_C2_cmplt",
+    "llvm.hexagon.C2.cmpltu" => "__builtin_HEXAGON_C2_cmpltu",
+    "llvm.hexagon.C2.mask" => "__builtin_HEXAGON_C2_mask",
+    "llvm.hexagon.C2.mux" => "__builtin_HEXAGON_C2_mux",
+    "llvm.hexagon.C2.muxii" => "__builtin_HEXAGON_C2_muxii",
+    "llvm.hexagon.C2.muxir" => "__builtin_HEXAGON_C2_muxir",
+    "llvm.hexagon.C2.muxri" => "__builtin_HEXAGON_C2_muxri",
+    "llvm.hexagon.C2.not" => "__builtin_HEXAGON_C2_not",
+    "llvm.hexagon.C2.or" => "__builtin_HEXAGON_C2_or",
+    "llvm.hexagon.C2.orn" => "__builtin_HEXAGON_C2_orn",
+    "llvm.hexagon.C2.pxfer.map" => "__builtin_HEXAGON_C2_pxfer_map",
+    "llvm.hexagon.C2.tfrpr" => "__builtin_HEXAGON_C2_tfrpr",
+    "llvm.hexagon.C2.tfrrp" => "__builtin_HEXAGON_C2_tfrrp",
+    "llvm.hexagon.C2.vitpack" => "__builtin_HEXAGON_C2_vitpack",
+    "llvm.hexagon.C2.vmux" => "__builtin_HEXAGON_C2_vmux",
+    "llvm.hexagon.C2.xor" => "__builtin_HEXAGON_C2_xor",
+    "llvm.hexagon.C4.and.and" => "__builtin_HEXAGON_C4_and_and",
+    "llvm.hexagon.C4.and.andn" => "__builtin_HEXAGON_C4_and_andn",
+    "llvm.hexagon.C4.and.or" => "__builtin_HEXAGON_C4_and_or",
+    "llvm.hexagon.C4.and.orn" => "__builtin_HEXAGON_C4_and_orn",
+    "llvm.hexagon.C4.cmplte" => "__builtin_HEXAGON_C4_cmplte",
+    "llvm.hexagon.C4.cmpltei" => "__builtin_HEXAGON_C4_cmpltei",
+    "llvm.hexagon.C4.cmplteu" => "__builtin_HEXAGON_C4_cmplteu",
+    "llvm.hexagon.C4.cmplteui" => "__builtin_HEXAGON_C4_cmplteui",
+    "llvm.hexagon.C4.cmpneq" => "__builtin_HEXAGON_C4_cmpneq",
+    "llvm.hexagon.C4.cmpneqi" => "__builtin_HEXAGON_C4_cmpneqi",
+    "llvm.hexagon.C4.fastcorner9" => "__builtin_HEXAGON_C4_fastcorner9",
+    "llvm.hexagon.C4.fastcorner9.not" => "__builtin_HEXAGON_C4_fastcorner9_not",
+    "llvm.hexagon.C4.nbitsclr" => "__builtin_HEXAGON_C4_nbitsclr",
+    "llvm.hexagon.C4.nbitsclri" => "__builtin_HEXAGON_C4_nbitsclri",
+    "llvm.hexagon.C4.nbitsset" => "__builtin_HEXAGON_C4_nbitsset",
+    "llvm.hexagon.C4.or.and" => "__builtin_HEXAGON_C4_or_and",
+    "llvm.hexagon.C4.or.andn" => "__builtin_HEXAGON_C4_or_andn",
+    "llvm.hexagon.C4.or.or" => "__builtin_HEXAGON_C4_or_or",
+    "llvm.hexagon.C4.or.orn" => "__builtin_HEXAGON_C4_or_orn",
+    "llvm.hexagon.F2.conv.d2df" => "__builtin_HEXAGON_F2_conv_d2df",
+    "llvm.hexagon.F2.conv.d2sf" => "__builtin_HEXAGON_F2_conv_d2sf",
+    "llvm.hexagon.F2.conv.df2d" => "__builtin_HEXAGON_F2_conv_df2d",
+    "llvm.hexagon.F2.conv.df2d.chop" => "__builtin_HEXAGON_F2_conv_df2d_chop",
+    "llvm.hexagon.F2.conv.df2sf" => "__builtin_HEXAGON_F2_conv_df2sf",
+    "llvm.hexagon.F2.conv.df2ud" => "__builtin_HEXAGON_F2_conv_df2ud",
+    "llvm.hexagon.F2.conv.df2ud.chop" => "__builtin_HEXAGON_F2_conv_df2ud_chop",
+    "llvm.hexagon.F2.conv.df2uw" => "__builtin_HEXAGON_F2_conv_df2uw",
+    "llvm.hexagon.F2.conv.df2uw.chop" => "__builtin_HEXAGON_F2_conv_df2uw_chop",
+    "llvm.hexagon.F2.conv.df2w" => "__builtin_HEXAGON_F2_conv_df2w",
+    "llvm.hexagon.F2.conv.df2w.chop" => "__builtin_HEXAGON_F2_conv_df2w_chop",
+    "llvm.hexagon.F2.conv.sf2d" => "__builtin_HEXAGON_F2_conv_sf2d",
+    "llvm.hexagon.F2.conv.sf2d.chop" => "__builtin_HEXAGON_F2_conv_sf2d_chop",
+    "llvm.hexagon.F2.conv.sf2df" => "__builtin_HEXAGON_F2_conv_sf2df",
+    "llvm.hexagon.F2.conv.sf2ud" => "__builtin_HEXAGON_F2_conv_sf2ud",
+    "llvm.hexagon.F2.conv.sf2ud.chop" => "__builtin_HEXAGON_F2_conv_sf2ud_chop",
+    "llvm.hexagon.F2.conv.sf2uw" => "__builtin_HEXAGON_F2_conv_sf2uw",
+    "llvm.hexagon.F2.conv.sf2uw.chop" => "__builtin_HEXAGON_F2_conv_sf2uw_chop",
+    "llvm.hexagon.F2.conv.sf2w" => "__builtin_HEXAGON_F2_conv_sf2w",
+    "llvm.hexagon.F2.conv.sf2w.chop" => "__builtin_HEXAGON_F2_conv_sf2w_chop",
+    "llvm.hexagon.F2.conv.ud2df" => "__builtin_HEXAGON_F2_conv_ud2df",
+    "llvm.hexagon.F2.conv.ud2sf" => "__builtin_HEXAGON_F2_conv_ud2sf",
+    "llvm.hexagon.F2.conv.uw2df" => "__builtin_HEXAGON_F2_conv_uw2df",
+    "llvm.hexagon.F2.conv.uw2sf" => "__builtin_HEXAGON_F2_conv_uw2sf",
+    "llvm.hexagon.F2.conv.w2df" => "__builtin_HEXAGON_F2_conv_w2df",
+    "llvm.hexagon.F2.conv.w2sf" => "__builtin_HEXAGON_F2_conv_w2sf",
+    "llvm.hexagon.F2.dfadd" => "__builtin_HEXAGON_F2_dfadd",
+    "llvm.hexagon.F2.dfclass" => "__builtin_HEXAGON_F2_dfclass",
+    "llvm.hexagon.F2.dfcmpeq" => "__builtin_HEXAGON_F2_dfcmpeq",
+    "llvm.hexagon.F2.dfcmpge" => "__builtin_HEXAGON_F2_dfcmpge",
+    "llvm.hexagon.F2.dfcmpgt" => "__builtin_HEXAGON_F2_dfcmpgt",
+    "llvm.hexagon.F2.dfcmpuo" => "__builtin_HEXAGON_F2_dfcmpuo",
+    "llvm.hexagon.F2.dffixupd" => "__builtin_HEXAGON_F2_dffixupd",
+    "llvm.hexagon.F2.dffixupn" => "__builtin_HEXAGON_F2_dffixupn",
+    "llvm.hexagon.F2.dffixupr" => "__builtin_HEXAGON_F2_dffixupr",
+    "llvm.hexagon.F2.dffma" => "__builtin_HEXAGON_F2_dffma",
+    "llvm.hexagon.F2.dffma.lib" => "__builtin_HEXAGON_F2_dffma_lib",
+    "llvm.hexagon.F2.dffma.sc" => "__builtin_HEXAGON_F2_dffma_sc",
+    "llvm.hexagon.F2.dffms" => "__builtin_HEXAGON_F2_dffms",
+    "llvm.hexagon.F2.dffms.lib" => "__builtin_HEXAGON_F2_dffms_lib",
+    "llvm.hexagon.F2.dfimm.n" => "__builtin_HEXAGON_F2_dfimm_n",
+    "llvm.hexagon.F2.dfimm.p" => "__builtin_HEXAGON_F2_dfimm_p",
+    "llvm.hexagon.F2.dfmax" => "__builtin_HEXAGON_F2_dfmax",
+    "llvm.hexagon.F2.dfmin" => "__builtin_HEXAGON_F2_dfmin",
+    "llvm.hexagon.F2.dfmpy" => "__builtin_HEXAGON_F2_dfmpy",
+    "llvm.hexagon.F2.dfsub" => "__builtin_HEXAGON_F2_dfsub",
+    "llvm.hexagon.F2.sfadd" => "__builtin_HEXAGON_F2_sfadd",
+    "llvm.hexagon.F2.sfclass" => "__builtin_HEXAGON_F2_sfclass",
+    "llvm.hexagon.F2.sfcmpeq" => "__builtin_HEXAGON_F2_sfcmpeq",
+    "llvm.hexagon.F2.sfcmpge" => "__builtin_HEXAGON_F2_sfcmpge",
+    "llvm.hexagon.F2.sfcmpgt" => "__builtin_HEXAGON_F2_sfcmpgt",
+    "llvm.hexagon.F2.sfcmpuo" => "__builtin_HEXAGON_F2_sfcmpuo",
+    "llvm.hexagon.F2.sffixupd" => "__builtin_HEXAGON_F2_sffixupd",
+    "llvm.hexagon.F2.sffixupn" => "__builtin_HEXAGON_F2_sffixupn",
+    "llvm.hexagon.F2.sffixupr" => "__builtin_HEXAGON_F2_sffixupr",
+    "llvm.hexagon.F2.sffma" => "__builtin_HEXAGON_F2_sffma",
+    "llvm.hexagon.F2.sffma.lib" => "__builtin_HEXAGON_F2_sffma_lib",
+    "llvm.hexagon.F2.sffma.sc" => "__builtin_HEXAGON_F2_sffma_sc",
+    "llvm.hexagon.F2.sffms" => "__builtin_HEXAGON_F2_sffms",
+    "llvm.hexagon.F2.sffms.lib" => "__builtin_HEXAGON_F2_sffms_lib",
+    "llvm.hexagon.F2.sfimm.n" => "__builtin_HEXAGON_F2_sfimm_n",
+    "llvm.hexagon.F2.sfimm.p" => "__builtin_HEXAGON_F2_sfimm_p",
+    "llvm.hexagon.F2.sfmax" => "__builtin_HEXAGON_F2_sfmax",
+    "llvm.hexagon.F2.sfmin" => "__builtin_HEXAGON_F2_sfmin",
+    "llvm.hexagon.F2.sfmpy" => "__builtin_HEXAGON_F2_sfmpy",
+    "llvm.hexagon.F2.sfsub" => "__builtin_HEXAGON_F2_sfsub",
+    "llvm.hexagon.M2.acci" => "__builtin_HEXAGON_M2_acci",
+    "llvm.hexagon.M2.accii" => "__builtin_HEXAGON_M2_accii",
+    "llvm.hexagon.M2.cmaci.s0" => "__builtin_HEXAGON_M2_cmaci_s0",
+    "llvm.hexagon.M2.cmacr.s0" => "__builtin_HEXAGON_M2_cmacr_s0",
+    "llvm.hexagon.M2.cmacs.s0" => "__builtin_HEXAGON_M2_cmacs_s0",
+    "llvm.hexagon.M2.cmacs.s1" => "__builtin_HEXAGON_M2_cmacs_s1",
+    "llvm.hexagon.M2.cmacsc.s0" => "__builtin_HEXAGON_M2_cmacsc_s0",
+    "llvm.hexagon.M2.cmacsc.s1" => "__builtin_HEXAGON_M2_cmacsc_s1",
+    "llvm.hexagon.M2.cmpyi.s0" => "__builtin_HEXAGON_M2_cmpyi_s0",
+    "llvm.hexagon.M2.cmpyr.s0" => "__builtin_HEXAGON_M2_cmpyr_s0",
+    "llvm.hexagon.M2.cmpyrs.s0" => "__builtin_HEXAGON_M2_cmpyrs_s0",
+    "llvm.hexagon.M2.cmpyrs.s1" => "__builtin_HEXAGON_M2_cmpyrs_s1",
+    "llvm.hexagon.M2.cmpyrsc.s0" => "__builtin_HEXAGON_M2_cmpyrsc_s0",
+    "llvm.hexagon.M2.cmpyrsc.s1" => "__builtin_HEXAGON_M2_cmpyrsc_s1",
+    "llvm.hexagon.M2.cmpys.s0" => "__builtin_HEXAGON_M2_cmpys_s0",
+    "llvm.hexagon.M2.cmpys.s1" => "__builtin_HEXAGON_M2_cmpys_s1",
+    "llvm.hexagon.M2.cmpysc.s0" => "__builtin_HEXAGON_M2_cmpysc_s0",
+    "llvm.hexagon.M2.cmpysc.s1" => "__builtin_HEXAGON_M2_cmpysc_s1",
+    "llvm.hexagon.M2.cnacs.s0" => "__builtin_HEXAGON_M2_cnacs_s0",
+    "llvm.hexagon.M2.cnacs.s1" => "__builtin_HEXAGON_M2_cnacs_s1",
+    "llvm.hexagon.M2.cnacsc.s0" => "__builtin_HEXAGON_M2_cnacsc_s0",
+    "llvm.hexagon.M2.cnacsc.s1" => "__builtin_HEXAGON_M2_cnacsc_s1",
+    "llvm.hexagon.M2.dpmpyss.acc.s0" => "__builtin_HEXAGON_M2_dpmpyss_acc_s0",
+    "llvm.hexagon.M2.dpmpyss.nac.s0" => "__builtin_HEXAGON_M2_dpmpyss_nac_s0",
+    "llvm.hexagon.M2.dpmpyss.rnd.s0" => "__builtin_HEXAGON_M2_dpmpyss_rnd_s0",
+    "llvm.hexagon.M2.dpmpyss.s0" => "__builtin_HEXAGON_M2_dpmpyss_s0",
+    "llvm.hexagon.M2.dpmpyuu.acc.s0" => "__builtin_HEXAGON_M2_dpmpyuu_acc_s0",
+    "llvm.hexagon.M2.dpmpyuu.nac.s0" => "__builtin_HEXAGON_M2_dpmpyuu_nac_s0",
+    "llvm.hexagon.M2.dpmpyuu.s0" => "__builtin_HEXAGON_M2_dpmpyuu_s0",
+    "llvm.hexagon.M2.hmmpyh.rs1" => "__builtin_HEXAGON_M2_hmmpyh_rs1",
+    "llvm.hexagon.M2.hmmpyh.s1" => "__builtin_HEXAGON_M2_hmmpyh_s1",
+    "llvm.hexagon.M2.hmmpyl.rs1" => "__builtin_HEXAGON_M2_hmmpyl_rs1",
+    "llvm.hexagon.M2.hmmpyl.s1" => "__builtin_HEXAGON_M2_hmmpyl_s1",
+    "llvm.hexagon.M2.maci" => "__builtin_HEXAGON_M2_maci",
+    "llvm.hexagon.M2.macsin" => "__builtin_HEXAGON_M2_macsin",
+    "llvm.hexagon.M2.macsip" => "__builtin_HEXAGON_M2_macsip",
+    "llvm.hexagon.M2.mmachs.rs0" => "__builtin_HEXAGON_M2_mmachs_rs0",
+    "llvm.hexagon.M2.mmachs.rs1" => "__builtin_HEXAGON_M2_mmachs_rs1",
+    "llvm.hexagon.M2.mmachs.s0" => "__builtin_HEXAGON_M2_mmachs_s0",
+    "llvm.hexagon.M2.mmachs.s1" => "__builtin_HEXAGON_M2_mmachs_s1",
+    "llvm.hexagon.M2.mmacls.rs0" => "__builtin_HEXAGON_M2_mmacls_rs0",
+    "llvm.hexagon.M2.mmacls.rs1" => "__builtin_HEXAGON_M2_mmacls_rs1",
+    "llvm.hexagon.M2.mmacls.s0" => "__builtin_HEXAGON_M2_mmacls_s0",
+    "llvm.hexagon.M2.mmacls.s1" => "__builtin_HEXAGON_M2_mmacls_s1",
+    "llvm.hexagon.M2.mmacuhs.rs0" => "__builtin_HEXAGON_M2_mmacuhs_rs0",
+    "llvm.hexagon.M2.mmacuhs.rs1" => "__builtin_HEXAGON_M2_mmacuhs_rs1",
+    "llvm.hexagon.M2.mmacuhs.s0" => "__builtin_HEXAGON_M2_mmacuhs_s0",
+    "llvm.hexagon.M2.mmacuhs.s1" => "__builtin_HEXAGON_M2_mmacuhs_s1",
+    "llvm.hexagon.M2.mmaculs.rs0" => "__builtin_HEXAGON_M2_mmaculs_rs0",
+    "llvm.hexagon.M2.mmaculs.rs1" => "__builtin_HEXAGON_M2_mmaculs_rs1",
+    "llvm.hexagon.M2.mmaculs.s0" => "__builtin_HEXAGON_M2_mmaculs_s0",
+    "llvm.hexagon.M2.mmaculs.s1" => "__builtin_HEXAGON_M2_mmaculs_s1",
+    "llvm.hexagon.M2.mmpyh.rs0" => "__builtin_HEXAGON_M2_mmpyh_rs0",
+    "llvm.hexagon.M2.mmpyh.rs1" => "__builtin_HEXAGON_M2_mmpyh_rs1",
+    "llvm.hexagon.M2.mmpyh.s0" => "__builtin_HEXAGON_M2_mmpyh_s0",
+    "llvm.hexagon.M2.mmpyh.s1" => "__builtin_HEXAGON_M2_mmpyh_s1",
+    "llvm.hexagon.M2.mmpyl.rs0" => "__builtin_HEXAGON_M2_mmpyl_rs0",
+    "llvm.hexagon.M2.mmpyl.rs1" => "__builtin_HEXAGON_M2_mmpyl_rs1",
+    "llvm.hexagon.M2.mmpyl.s0" => "__builtin_HEXAGON_M2_mmpyl_s0",
+    "llvm.hexagon.M2.mmpyl.s1" => "__builtin_HEXAGON_M2_mmpyl_s1",
+    "llvm.hexagon.M2.mmpyuh.rs0" => "__builtin_HEXAGON_M2_mmpyuh_rs0",
+    "llvm.hexagon.M2.mmpyuh.rs1" => "__builtin_HEXAGON_M2_mmpyuh_rs1",
+    "llvm.hexagon.M2.mmpyuh.s0" => "__builtin_HEXAGON_M2_mmpyuh_s0",
+    "llvm.hexagon.M2.mmpyuh.s1" => "__builtin_HEXAGON_M2_mmpyuh_s1",
+    "llvm.hexagon.M2.mmpyul.rs0" => "__builtin_HEXAGON_M2_mmpyul_rs0",
+    "llvm.hexagon.M2.mmpyul.rs1" => "__builtin_HEXAGON_M2_mmpyul_rs1",
+    "llvm.hexagon.M2.mmpyul.s0" => "__builtin_HEXAGON_M2_mmpyul_s0",
+    "llvm.hexagon.M2.mmpyul.s1" => "__builtin_HEXAGON_M2_mmpyul_s1",
+    "llvm.hexagon.M2.mpy.acc.hh.s0" => "__builtin_HEXAGON_M2_mpy_acc_hh_s0",
+    "llvm.hexagon.M2.mpy.acc.hh.s1" => "__builtin_HEXAGON_M2_mpy_acc_hh_s1",
+    "llvm.hexagon.M2.mpy.acc.hl.s0" => "__builtin_HEXAGON_M2_mpy_acc_hl_s0",
+    "llvm.hexagon.M2.mpy.acc.hl.s1" => "__builtin_HEXAGON_M2_mpy_acc_hl_s1",
+    "llvm.hexagon.M2.mpy.acc.lh.s0" => "__builtin_HEXAGON_M2_mpy_acc_lh_s0",
+    "llvm.hexagon.M2.mpy.acc.lh.s1" => "__builtin_HEXAGON_M2_mpy_acc_lh_s1",
+    "llvm.hexagon.M2.mpy.acc.ll.s0" => "__builtin_HEXAGON_M2_mpy_acc_ll_s0",
+    "llvm.hexagon.M2.mpy.acc.ll.s1" => "__builtin_HEXAGON_M2_mpy_acc_ll_s1",
+    "llvm.hexagon.M2.mpy.acc.sat.hh.s0" => "__builtin_HEXAGON_M2_mpy_acc_sat_hh_s0",
+    "llvm.hexagon.M2.mpy.acc.sat.hh.s1" => "__builtin_HEXAGON_M2_mpy_acc_sat_hh_s1",
+    "llvm.hexagon.M2.mpy.acc.sat.hl.s0" => "__builtin_HEXAGON_M2_mpy_acc_sat_hl_s0",
+    "llvm.hexagon.M2.mpy.acc.sat.hl.s1" => "__builtin_HEXAGON_M2_mpy_acc_sat_hl_s1",
+    "llvm.hexagon.M2.mpy.acc.sat.lh.s0" => "__builtin_HEXAGON_M2_mpy_acc_sat_lh_s0",
+    "llvm.hexagon.M2.mpy.acc.sat.lh.s1" => "__builtin_HEXAGON_M2_mpy_acc_sat_lh_s1",
+    "llvm.hexagon.M2.mpy.acc.sat.ll.s0" => "__builtin_HEXAGON_M2_mpy_acc_sat_ll_s0",
+    "llvm.hexagon.M2.mpy.acc.sat.ll.s1" => "__builtin_HEXAGON_M2_mpy_acc_sat_ll_s1",
+    "llvm.hexagon.M2.mpy.hh.s0" => "__builtin_HEXAGON_M2_mpy_hh_s0",
+    "llvm.hexagon.M2.mpy.hh.s1" => "__builtin_HEXAGON_M2_mpy_hh_s1",
+    "llvm.hexagon.M2.mpy.hl.s0" => "__builtin_HEXAGON_M2_mpy_hl_s0",
+    "llvm.hexagon.M2.mpy.hl.s1" => "__builtin_HEXAGON_M2_mpy_hl_s1",
+    "llvm.hexagon.M2.mpy.lh.s0" => "__builtin_HEXAGON_M2_mpy_lh_s0",
+    "llvm.hexagon.M2.mpy.lh.s1" => "__builtin_HEXAGON_M2_mpy_lh_s1",
+    "llvm.hexagon.M2.mpy.ll.s0" => "__builtin_HEXAGON_M2_mpy_ll_s0",
+    "llvm.hexagon.M2.mpy.ll.s1" => "__builtin_HEXAGON_M2_mpy_ll_s1",
+    "llvm.hexagon.M2.mpy.nac.hh.s0" => "__builtin_HEXAGON_M2_mpy_nac_hh_s0",
+    "llvm.hexagon.M2.mpy.nac.hh.s1" => "__builtin_HEXAGON_M2_mpy_nac_hh_s1",
+    "llvm.hexagon.M2.mpy.nac.hl.s0" => "__builtin_HEXAGON_M2_mpy_nac_hl_s0",
+    "llvm.hexagon.M2.mpy.nac.hl.s1" => "__builtin_HEXAGON_M2_mpy_nac_hl_s1",
+    "llvm.hexagon.M2.mpy.nac.lh.s0" => "__builtin_HEXAGON_M2_mpy_nac_lh_s0",
+    "llvm.hexagon.M2.mpy.nac.lh.s1" => "__builtin_HEXAGON_M2_mpy_nac_lh_s1",
+    "llvm.hexagon.M2.mpy.nac.ll.s0" => "__builtin_HEXAGON_M2_mpy_nac_ll_s0",
+    "llvm.hexagon.M2.mpy.nac.ll.s1" => "__builtin_HEXAGON_M2_mpy_nac_ll_s1",
+    "llvm.hexagon.M2.mpy.nac.sat.hh.s0" => "__builtin_HEXAGON_M2_mpy_nac_sat_hh_s0",
+    "llvm.hexagon.M2.mpy.nac.sat.hh.s1" => "__builtin_HEXAGON_M2_mpy_nac_sat_hh_s1",
+    "llvm.hexagon.M2.mpy.nac.sat.hl.s0" => "__builtin_HEXAGON_M2_mpy_nac_sat_hl_s0",
+    "llvm.hexagon.M2.mpy.nac.sat.hl.s1" => "__builtin_HEXAGON_M2_mpy_nac_sat_hl_s1",
+    "llvm.hexagon.M2.mpy.nac.sat.lh.s0" => "__builtin_HEXAGON_M2_mpy_nac_sat_lh_s0",
+    "llvm.hexagon.M2.mpy.nac.sat.lh.s1" => "__builtin_HEXAGON_M2_mpy_nac_sat_lh_s1",
+    "llvm.hexagon.M2.mpy.nac.sat.ll.s0" => "__builtin_HEXAGON_M2_mpy_nac_sat_ll_s0",
+    "llvm.hexagon.M2.mpy.nac.sat.ll.s1" => "__builtin_HEXAGON_M2_mpy_nac_sat_ll_s1",
+    "llvm.hexagon.M2.mpy.rnd.hh.s0" => "__builtin_HEXAGON_M2_mpy_rnd_hh_s0",
+    "llvm.hexagon.M2.mpy.rnd.hh.s1" => "__builtin_HEXAGON_M2_mpy_rnd_hh_s1",
+    "llvm.hexagon.M2.mpy.rnd.hl.s0" => "__builtin_HEXAGON_M2_mpy_rnd_hl_s0",
+    "llvm.hexagon.M2.mpy.rnd.hl.s1" => "__builtin_HEXAGON_M2_mpy_rnd_hl_s1",
+    "llvm.hexagon.M2.mpy.rnd.lh.s0" => "__builtin_HEXAGON_M2_mpy_rnd_lh_s0",
+    "llvm.hexagon.M2.mpy.rnd.lh.s1" => "__builtin_HEXAGON_M2_mpy_rnd_lh_s1",
+    "llvm.hexagon.M2.mpy.rnd.ll.s0" => "__builtin_HEXAGON_M2_mpy_rnd_ll_s0",
+    "llvm.hexagon.M2.mpy.rnd.ll.s1" => "__builtin_HEXAGON_M2_mpy_rnd_ll_s1",
+    "llvm.hexagon.M2.mpy.sat.hh.s0" => "__builtin_HEXAGON_M2_mpy_sat_hh_s0",
+    "llvm.hexagon.M2.mpy.sat.hh.s1" => "__builtin_HEXAGON_M2_mpy_sat_hh_s1",
+    "llvm.hexagon.M2.mpy.sat.hl.s0" => "__builtin_HEXAGON_M2_mpy_sat_hl_s0",
+    "llvm.hexagon.M2.mpy.sat.hl.s1" => "__builtin_HEXAGON_M2_mpy_sat_hl_s1",
+    "llvm.hexagon.M2.mpy.sat.lh.s0" => "__builtin_HEXAGON_M2_mpy_sat_lh_s0",
+    "llvm.hexagon.M2.mpy.sat.lh.s1" => "__builtin_HEXAGON_M2_mpy_sat_lh_s1",
+    "llvm.hexagon.M2.mpy.sat.ll.s0" => "__builtin_HEXAGON_M2_mpy_sat_ll_s0",
+    "llvm.hexagon.M2.mpy.sat.ll.s1" => "__builtin_HEXAGON_M2_mpy_sat_ll_s1",
+    "llvm.hexagon.M2.mpy.sat.rnd.hh.s0" => "__builtin_HEXAGON_M2_mpy_sat_rnd_hh_s0",
+    "llvm.hexagon.M2.mpy.sat.rnd.hh.s1" => "__builtin_HEXAGON_M2_mpy_sat_rnd_hh_s1",
+    "llvm.hexagon.M2.mpy.sat.rnd.hl.s0" => "__builtin_HEXAGON_M2_mpy_sat_rnd_hl_s0",
+    "llvm.hexagon.M2.mpy.sat.rnd.hl.s1" => "__builtin_HEXAGON_M2_mpy_sat_rnd_hl_s1",
+    "llvm.hexagon.M2.mpy.sat.rnd.lh.s0" => "__builtin_HEXAGON_M2_mpy_sat_rnd_lh_s0",
+    "llvm.hexagon.M2.mpy.sat.rnd.lh.s1" => "__builtin_HEXAGON_M2_mpy_sat_rnd_lh_s1",
+    "llvm.hexagon.M2.mpy.sat.rnd.ll.s0" => "__builtin_HEXAGON_M2_mpy_sat_rnd_ll_s0",
+    "llvm.hexagon.M2.mpy.sat.rnd.ll.s1" => "__builtin_HEXAGON_M2_mpy_sat_rnd_ll_s1",
+    "llvm.hexagon.M2.mpy.up" => "__builtin_HEXAGON_M2_mpy_up",
+    "llvm.hexagon.M2.mpy.up.s1" => "__builtin_HEXAGON_M2_mpy_up_s1",
+    "llvm.hexagon.M2.mpy.up.s1.sat" => "__builtin_HEXAGON_M2_mpy_up_s1_sat",
+    "llvm.hexagon.M2.mpyd.acc.hh.s0" => "__builtin_HEXAGON_M2_mpyd_acc_hh_s0",
+    "llvm.hexagon.M2.mpyd.acc.hh.s1" => "__builtin_HEXAGON_M2_mpyd_acc_hh_s1",
+    "llvm.hexagon.M2.mpyd.acc.hl.s0" => "__builtin_HEXAGON_M2_mpyd_acc_hl_s0",
+    "llvm.hexagon.M2.mpyd.acc.hl.s1" => "__builtin_HEXAGON_M2_mpyd_acc_hl_s1",
+    "llvm.hexagon.M2.mpyd.acc.lh.s0" => "__builtin_HEXAGON_M2_mpyd_acc_lh_s0",
+    "llvm.hexagon.M2.mpyd.acc.lh.s1" => "__builtin_HEXAGON_M2_mpyd_acc_lh_s1",
+    "llvm.hexagon.M2.mpyd.acc.ll.s0" => "__builtin_HEXAGON_M2_mpyd_acc_ll_s0",
+    "llvm.hexagon.M2.mpyd.acc.ll.s1" => "__builtin_HEXAGON_M2_mpyd_acc_ll_s1",
+    "llvm.hexagon.M2.mpyd.hh.s0" => "__builtin_HEXAGON_M2_mpyd_hh_s0",
+    "llvm.hexagon.M2.mpyd.hh.s1" => "__builtin_HEXAGON_M2_mpyd_hh_s1",
+    "llvm.hexagon.M2.mpyd.hl.s0" => "__builtin_HEXAGON_M2_mpyd_hl_s0",
+    "llvm.hexagon.M2.mpyd.hl.s1" => "__builtin_HEXAGON_M2_mpyd_hl_s1",
+    "llvm.hexagon.M2.mpyd.lh.s0" => "__builtin_HEXAGON_M2_mpyd_lh_s0",
+    "llvm.hexagon.M2.mpyd.lh.s1" => "__builtin_HEXAGON_M2_mpyd_lh_s1",
+    "llvm.hexagon.M2.mpyd.ll.s0" => "__builtin_HEXAGON_M2_mpyd_ll_s0",
+    "llvm.hexagon.M2.mpyd.ll.s1" => "__builtin_HEXAGON_M2_mpyd_ll_s1",
+    "llvm.hexagon.M2.mpyd.nac.hh.s0" => "__builtin_HEXAGON_M2_mpyd_nac_hh_s0",
+    "llvm.hexagon.M2.mpyd.nac.hh.s1" => "__builtin_HEXAGON_M2_mpyd_nac_hh_s1",
+    "llvm.hexagon.M2.mpyd.nac.hl.s0" => "__builtin_HEXAGON_M2_mpyd_nac_hl_s0",
+    "llvm.hexagon.M2.mpyd.nac.hl.s1" => "__builtin_HEXAGON_M2_mpyd_nac_hl_s1",
+    "llvm.hexagon.M2.mpyd.nac.lh.s0" => "__builtin_HEXAGON_M2_mpyd_nac_lh_s0",
+    "llvm.hexagon.M2.mpyd.nac.lh.s1" => "__builtin_HEXAGON_M2_mpyd_nac_lh_s1",
+    "llvm.hexagon.M2.mpyd.nac.ll.s0" => "__builtin_HEXAGON_M2_mpyd_nac_ll_s0",
+    "llvm.hexagon.M2.mpyd.nac.ll.s1" => "__builtin_HEXAGON_M2_mpyd_nac_ll_s1",
+    "llvm.hexagon.M2.mpyd.rnd.hh.s0" => "__builtin_HEXAGON_M2_mpyd_rnd_hh_s0",
+    "llvm.hexagon.M2.mpyd.rnd.hh.s1" => "__builtin_HEXAGON_M2_mpyd_rnd_hh_s1",
+    "llvm.hexagon.M2.mpyd.rnd.hl.s0" => "__builtin_HEXAGON_M2_mpyd_rnd_hl_s0",
+    "llvm.hexagon.M2.mpyd.rnd.hl.s1" => "__builtin_HEXAGON_M2_mpyd_rnd_hl_s1",
+    "llvm.hexagon.M2.mpyd.rnd.lh.s0" => "__builtin_HEXAGON_M2_mpyd_rnd_lh_s0",
+    "llvm.hexagon.M2.mpyd.rnd.lh.s1" => "__builtin_HEXAGON_M2_mpyd_rnd_lh_s1",
+    "llvm.hexagon.M2.mpyd.rnd.ll.s0" => "__builtin_HEXAGON_M2_mpyd_rnd_ll_s0",
+    "llvm.hexagon.M2.mpyd.rnd.ll.s1" => "__builtin_HEXAGON_M2_mpyd_rnd_ll_s1",
+    "llvm.hexagon.M2.mpyi" => "__builtin_HEXAGON_M2_mpyi",
+    "llvm.hexagon.M2.mpysmi" => "__builtin_HEXAGON_M2_mpysmi",
+    "llvm.hexagon.M2.mpysu.up" => "__builtin_HEXAGON_M2_mpysu_up",
+    "llvm.hexagon.M2.mpyu.acc.hh.s0" => "__builtin_HEXAGON_M2_mpyu_acc_hh_s0",
+    "llvm.hexagon.M2.mpyu.acc.hh.s1" => "__builtin_HEXAGON_M2_mpyu_acc_hh_s1",
+    "llvm.hexagon.M2.mpyu.acc.hl.s0" => "__builtin_HEXAGON_M2_mpyu_acc_hl_s0",
+    "llvm.hexagon.M2.mpyu.acc.hl.s1" => "__builtin_HEXAGON_M2_mpyu_acc_hl_s1",
+    "llvm.hexagon.M2.mpyu.acc.lh.s0" => "__builtin_HEXAGON_M2_mpyu_acc_lh_s0",
+    "llvm.hexagon.M2.mpyu.acc.lh.s1" => "__builtin_HEXAGON_M2_mpyu_acc_lh_s1",
+    "llvm.hexagon.M2.mpyu.acc.ll.s0" => "__builtin_HEXAGON_M2_mpyu_acc_ll_s0",
+    "llvm.hexagon.M2.mpyu.acc.ll.s1" => "__builtin_HEXAGON_M2_mpyu_acc_ll_s1",
+    "llvm.hexagon.M2.mpyu.hh.s0" => "__builtin_HEXAGON_M2_mpyu_hh_s0",
+    "llvm.hexagon.M2.mpyu.hh.s1" => "__builtin_HEXAGON_M2_mpyu_hh_s1",
+    "llvm.hexagon.M2.mpyu.hl.s0" => "__builtin_HEXAGON_M2_mpyu_hl_s0",
+    "llvm.hexagon.M2.mpyu.hl.s1" => "__builtin_HEXAGON_M2_mpyu_hl_s1",
+    "llvm.hexagon.M2.mpyu.lh.s0" => "__builtin_HEXAGON_M2_mpyu_lh_s0",
+    "llvm.hexagon.M2.mpyu.lh.s1" => "__builtin_HEXAGON_M2_mpyu_lh_s1",
+    "llvm.hexagon.M2.mpyu.ll.s0" => "__builtin_HEXAGON_M2_mpyu_ll_s0",
+    "llvm.hexagon.M2.mpyu.ll.s1" => "__builtin_HEXAGON_M2_mpyu_ll_s1",
+    "llvm.hexagon.M2.mpyu.nac.hh.s0" => "__builtin_HEXAGON_M2_mpyu_nac_hh_s0",
+    "llvm.hexagon.M2.mpyu.nac.hh.s1" => "__builtin_HEXAGON_M2_mpyu_nac_hh_s1",
+    "llvm.hexagon.M2.mpyu.nac.hl.s0" => "__builtin_HEXAGON_M2_mpyu_nac_hl_s0",
+    "llvm.hexagon.M2.mpyu.nac.hl.s1" => "__builtin_HEXAGON_M2_mpyu_nac_hl_s1",
+    "llvm.hexagon.M2.mpyu.nac.lh.s0" => "__builtin_HEXAGON_M2_mpyu_nac_lh_s0",
+    "llvm.hexagon.M2.mpyu.nac.lh.s1" => "__builtin_HEXAGON_M2_mpyu_nac_lh_s1",
+    "llvm.hexagon.M2.mpyu.nac.ll.s0" => "__builtin_HEXAGON_M2_mpyu_nac_ll_s0",
+    "llvm.hexagon.M2.mpyu.nac.ll.s1" => "__builtin_HEXAGON_M2_mpyu_nac_ll_s1",
+    "llvm.hexagon.M2.mpyu.up" => "__builtin_HEXAGON_M2_mpyu_up",
+    "llvm.hexagon.M2.mpyud.acc.hh.s0" => "__builtin_HEXAGON_M2_mpyud_acc_hh_s0",
+    "llvm.hexagon.M2.mpyud.acc.hh.s1" => "__builtin_HEXAGON_M2_mpyud_acc_hh_s1",
+    "llvm.hexagon.M2.mpyud.acc.hl.s0" => "__builtin_HEXAGON_M2_mpyud_acc_hl_s0",
+    "llvm.hexagon.M2.mpyud.acc.hl.s1" => "__builtin_HEXAGON_M2_mpyud_acc_hl_s1",
+    "llvm.hexagon.M2.mpyud.acc.lh.s0" => "__builtin_HEXAGON_M2_mpyud_acc_lh_s0",
+    "llvm.hexagon.M2.mpyud.acc.lh.s1" => "__builtin_HEXAGON_M2_mpyud_acc_lh_s1",
+    "llvm.hexagon.M2.mpyud.acc.ll.s0" => "__builtin_HEXAGON_M2_mpyud_acc_ll_s0",
+    "llvm.hexagon.M2.mpyud.acc.ll.s1" => "__builtin_HEXAGON_M2_mpyud_acc_ll_s1",
+    "llvm.hexagon.M2.mpyud.hh.s0" => "__builtin_HEXAGON_M2_mpyud_hh_s0",
+    "llvm.hexagon.M2.mpyud.hh.s1" => "__builtin_HEXAGON_M2_mpyud_hh_s1",
+    "llvm.hexagon.M2.mpyud.hl.s0" => "__builtin_HEXAGON_M2_mpyud_hl_s0",
+    "llvm.hexagon.M2.mpyud.hl.s1" => "__builtin_HEXAGON_M2_mpyud_hl_s1",
+    "llvm.hexagon.M2.mpyud.lh.s0" => "__builtin_HEXAGON_M2_mpyud_lh_s0",
+    "llvm.hexagon.M2.mpyud.lh.s1" => "__builtin_HEXAGON_M2_mpyud_lh_s1",
+    "llvm.hexagon.M2.mpyud.ll.s0" => "__builtin_HEXAGON_M2_mpyud_ll_s0",
+    "llvm.hexagon.M2.mpyud.ll.s1" => "__builtin_HEXAGON_M2_mpyud_ll_s1",
+    "llvm.hexagon.M2.mpyud.nac.hh.s0" => "__builtin_HEXAGON_M2_mpyud_nac_hh_s0",
+    "llvm.hexagon.M2.mpyud.nac.hh.s1" => "__builtin_HEXAGON_M2_mpyud_nac_hh_s1",
+    "llvm.hexagon.M2.mpyud.nac.hl.s0" => "__builtin_HEXAGON_M2_mpyud_nac_hl_s0",
+    "llvm.hexagon.M2.mpyud.nac.hl.s1" => "__builtin_HEXAGON_M2_mpyud_nac_hl_s1",
+    "llvm.hexagon.M2.mpyud.nac.lh.s0" => "__builtin_HEXAGON_M2_mpyud_nac_lh_s0",
+    "llvm.hexagon.M2.mpyud.nac.lh.s1" => "__builtin_HEXAGON_M2_mpyud_nac_lh_s1",
+    "llvm.hexagon.M2.mpyud.nac.ll.s0" => "__builtin_HEXAGON_M2_mpyud_nac_ll_s0",
+    "llvm.hexagon.M2.mpyud.nac.ll.s1" => "__builtin_HEXAGON_M2_mpyud_nac_ll_s1",
+    "llvm.hexagon.M2.mpyui" => "__builtin_HEXAGON_M2_mpyui",
+    "llvm.hexagon.M2.nacci" => "__builtin_HEXAGON_M2_nacci",
+    "llvm.hexagon.M2.naccii" => "__builtin_HEXAGON_M2_naccii",
+    "llvm.hexagon.M2.subacc" => "__builtin_HEXAGON_M2_subacc",
+    "llvm.hexagon.M2.vabsdiffh" => "__builtin_HEXAGON_M2_vabsdiffh",
+    "llvm.hexagon.M2.vabsdiffw" => "__builtin_HEXAGON_M2_vabsdiffw",
+    "llvm.hexagon.M2.vcmac.s0.sat.i" => "__builtin_HEXAGON_M2_vcmac_s0_sat_i",
+    "llvm.hexagon.M2.vcmac.s0.sat.r" => "__builtin_HEXAGON_M2_vcmac_s0_sat_r",
+    "llvm.hexagon.M2.vcmpy.s0.sat.i" => "__builtin_HEXAGON_M2_vcmpy_s0_sat_i",
+    "llvm.hexagon.M2.vcmpy.s0.sat.r" => "__builtin_HEXAGON_M2_vcmpy_s0_sat_r",
+    "llvm.hexagon.M2.vcmpy.s1.sat.i" => "__builtin_HEXAGON_M2_vcmpy_s1_sat_i",
+    "llvm.hexagon.M2.vcmpy.s1.sat.r" => "__builtin_HEXAGON_M2_vcmpy_s1_sat_r",
+    "llvm.hexagon.M2.vdmacs.s0" => "__builtin_HEXAGON_M2_vdmacs_s0",
+    "llvm.hexagon.M2.vdmacs.s1" => "__builtin_HEXAGON_M2_vdmacs_s1",
+    "llvm.hexagon.M2.vdmpyrs.s0" => "__builtin_HEXAGON_M2_vdmpyrs_s0",
+    "llvm.hexagon.M2.vdmpyrs.s1" => "__builtin_HEXAGON_M2_vdmpyrs_s1",
+    "llvm.hexagon.M2.vdmpys.s0" => "__builtin_HEXAGON_M2_vdmpys_s0",
+    "llvm.hexagon.M2.vdmpys.s1" => "__builtin_HEXAGON_M2_vdmpys_s1",
+    "llvm.hexagon.M2.vmac2" => "__builtin_HEXAGON_M2_vmac2",
+    "llvm.hexagon.M2.vmac2es" => "__builtin_HEXAGON_M2_vmac2es",
+    "llvm.hexagon.M2.vmac2es.s0" => "__builtin_HEXAGON_M2_vmac2es_s0",
+    "llvm.hexagon.M2.vmac2es.s1" => "__builtin_HEXAGON_M2_vmac2es_s1",
+    "llvm.hexagon.M2.vmac2s.s0" => "__builtin_HEXAGON_M2_vmac2s_s0",
+    "llvm.hexagon.M2.vmac2s.s1" => "__builtin_HEXAGON_M2_vmac2s_s1",
+    "llvm.hexagon.M2.vmac2su.s0" => "__builtin_HEXAGON_M2_vmac2su_s0",
+    "llvm.hexagon.M2.vmac2su.s1" => "__builtin_HEXAGON_M2_vmac2su_s1",
+    "llvm.hexagon.M2.vmpy2es.s0" => "__builtin_HEXAGON_M2_vmpy2es_s0",
+    "llvm.hexagon.M2.vmpy2es.s1" => "__builtin_HEXAGON_M2_vmpy2es_s1",
+    "llvm.hexagon.M2.vmpy2s.s0" => "__builtin_HEXAGON_M2_vmpy2s_s0",
+    "llvm.hexagon.M2.vmpy2s.s0pack" => "__builtin_HEXAGON_M2_vmpy2s_s0pack",
+    "llvm.hexagon.M2.vmpy2s.s1" => "__builtin_HEXAGON_M2_vmpy2s_s1",
+    "llvm.hexagon.M2.vmpy2s.s1pack" => "__builtin_HEXAGON_M2_vmpy2s_s1pack",
+    "llvm.hexagon.M2.vmpy2su.s0" => "__builtin_HEXAGON_M2_vmpy2su_s0",
+    "llvm.hexagon.M2.vmpy2su.s1" => "__builtin_HEXAGON_M2_vmpy2su_s1",
+    "llvm.hexagon.M2.vraddh" => "__builtin_HEXAGON_M2_vraddh",
+    "llvm.hexagon.M2.vradduh" => "__builtin_HEXAGON_M2_vradduh",
+    "llvm.hexagon.M2.vrcmaci.s0" => "__builtin_HEXAGON_M2_vrcmaci_s0",
+    "llvm.hexagon.M2.vrcmaci.s0c" => "__builtin_HEXAGON_M2_vrcmaci_s0c",
+    "llvm.hexagon.M2.vrcmacr.s0" => "__builtin_HEXAGON_M2_vrcmacr_s0",
+    "llvm.hexagon.M2.vrcmacr.s0c" => "__builtin_HEXAGON_M2_vrcmacr_s0c",
+    "llvm.hexagon.M2.vrcmpyi.s0" => "__builtin_HEXAGON_M2_vrcmpyi_s0",
+    "llvm.hexagon.M2.vrcmpyi.s0c" => "__builtin_HEXAGON_M2_vrcmpyi_s0c",
+    "llvm.hexagon.M2.vrcmpyr.s0" => "__builtin_HEXAGON_M2_vrcmpyr_s0",
+    "llvm.hexagon.M2.vrcmpyr.s0c" => "__builtin_HEXAGON_M2_vrcmpyr_s0c",
+    "llvm.hexagon.M2.vrcmpys.acc.s1" => "__builtin_HEXAGON_M2_vrcmpys_acc_s1",
+    "llvm.hexagon.M2.vrcmpys.s1" => "__builtin_HEXAGON_M2_vrcmpys_s1",
+    "llvm.hexagon.M2.vrcmpys.s1rp" => "__builtin_HEXAGON_M2_vrcmpys_s1rp",
+    "llvm.hexagon.M2.vrmac.s0" => "__builtin_HEXAGON_M2_vrmac_s0",
+    "llvm.hexagon.M2.vrmpy.s0" => "__builtin_HEXAGON_M2_vrmpy_s0",
+    "llvm.hexagon.M2.xor.xacc" => "__builtin_HEXAGON_M2_xor_xacc",
+    "llvm.hexagon.M4.and.and" => "__builtin_HEXAGON_M4_and_and",
+    "llvm.hexagon.M4.and.andn" => "__builtin_HEXAGON_M4_and_andn",
+    "llvm.hexagon.M4.and.or" => "__builtin_HEXAGON_M4_and_or",
+    "llvm.hexagon.M4.and.xor" => "__builtin_HEXAGON_M4_and_xor",
+    "llvm.hexagon.M4.cmpyi.wh" => "__builtin_HEXAGON_M4_cmpyi_wh",
+    "llvm.hexagon.M4.cmpyi.whc" => "__builtin_HEXAGON_M4_cmpyi_whc",
+    "llvm.hexagon.M4.cmpyr.wh" => "__builtin_HEXAGON_M4_cmpyr_wh",
+    "llvm.hexagon.M4.cmpyr.whc" => "__builtin_HEXAGON_M4_cmpyr_whc",
+    "llvm.hexagon.M4.mac.up.s1.sat" => "__builtin_HEXAGON_M4_mac_up_s1_sat",
+    "llvm.hexagon.M4.mpyri.addi" => "__builtin_HEXAGON_M4_mpyri_addi",
+    "llvm.hexagon.M4.mpyri.addr" => "__builtin_HEXAGON_M4_mpyri_addr",
+    "llvm.hexagon.M4.mpyri.addr.u2" => "__builtin_HEXAGON_M4_mpyri_addr_u2",
+    "llvm.hexagon.M4.mpyrr.addi" => "__builtin_HEXAGON_M4_mpyrr_addi",
+    "llvm.hexagon.M4.mpyrr.addr" => "__builtin_HEXAGON_M4_mpyrr_addr",
+    "llvm.hexagon.M4.nac.up.s1.sat" => "__builtin_HEXAGON_M4_nac_up_s1_sat",
+    "llvm.hexagon.M4.or.and" => "__builtin_HEXAGON_M4_or_and",
+    "llvm.hexagon.M4.or.andn" => "__builtin_HEXAGON_M4_or_andn",
+    "llvm.hexagon.M4.or.or" => "__builtin_HEXAGON_M4_or_or",
+    "llvm.hexagon.M4.or.xor" => "__builtin_HEXAGON_M4_or_xor",
+    "llvm.hexagon.M4.pmpyw" => "__builtin_HEXAGON_M4_pmpyw",
+    "llvm.hexagon.M4.pmpyw.acc" => "__builtin_HEXAGON_M4_pmpyw_acc",
+    "llvm.hexagon.M4.vpmpyh" => "__builtin_HEXAGON_M4_vpmpyh",
+    "llvm.hexagon.M4.vpmpyh.acc" => "__builtin_HEXAGON_M4_vpmpyh_acc",
+    "llvm.hexagon.M4.vrmpyeh.acc.s0" => "__builtin_HEXAGON_M4_vrmpyeh_acc_s0",
+    "llvm.hexagon.M4.vrmpyeh.acc.s1" => "__builtin_HEXAGON_M4_vrmpyeh_acc_s1",
+    "llvm.hexagon.M4.vrmpyeh.s0" => "__builtin_HEXAGON_M4_vrmpyeh_s0",
+    "llvm.hexagon.M4.vrmpyeh.s1" => "__builtin_HEXAGON_M4_vrmpyeh_s1",
+    "llvm.hexagon.M4.vrmpyoh.acc.s0" => "__builtin_HEXAGON_M4_vrmpyoh_acc_s0",
+    "llvm.hexagon.M4.vrmpyoh.acc.s1" => "__builtin_HEXAGON_M4_vrmpyoh_acc_s1",
+    "llvm.hexagon.M4.vrmpyoh.s0" => "__builtin_HEXAGON_M4_vrmpyoh_s0",
+    "llvm.hexagon.M4.vrmpyoh.s1" => "__builtin_HEXAGON_M4_vrmpyoh_s1",
+    "llvm.hexagon.M4.xor.and" => "__builtin_HEXAGON_M4_xor_and",
+    "llvm.hexagon.M4.xor.andn" => "__builtin_HEXAGON_M4_xor_andn",
+    "llvm.hexagon.M4.xor.or" => "__builtin_HEXAGON_M4_xor_or",
+    "llvm.hexagon.M4.xor.xacc" => "__builtin_HEXAGON_M4_xor_xacc",
+    "llvm.hexagon.M5.vdmacbsu" => "__builtin_HEXAGON_M5_vdmacbsu",
+    "llvm.hexagon.M5.vdmpybsu" => "__builtin_HEXAGON_M5_vdmpybsu",
+    "llvm.hexagon.M5.vmacbsu" => "__builtin_HEXAGON_M5_vmacbsu",
+    "llvm.hexagon.M5.vmacbuu" => "__builtin_HEXAGON_M5_vmacbuu",
+    "llvm.hexagon.M5.vmpybsu" => "__builtin_HEXAGON_M5_vmpybsu",
+    "llvm.hexagon.M5.vmpybuu" => "__builtin_HEXAGON_M5_vmpybuu",
+    "llvm.hexagon.M5.vrmacbsu" => "__builtin_HEXAGON_M5_vrmacbsu",
+    "llvm.hexagon.M5.vrmacbuu" => "__builtin_HEXAGON_M5_vrmacbuu",
+    "llvm.hexagon.M5.vrmpybsu" => "__builtin_HEXAGON_M5_vrmpybsu",
+    "llvm.hexagon.M5.vrmpybuu" => "__builtin_HEXAGON_M5_vrmpybuu",
+    "llvm.hexagon.M6.vabsdiffb" => "__builtin_HEXAGON_M6_vabsdiffb",
+    "llvm.hexagon.M6.vabsdiffub" => "__builtin_HEXAGON_M6_vabsdiffub",
+    "llvm.hexagon.S2.addasl.rrri" => "__builtin_HEXAGON_S2_addasl_rrri",
+    "llvm.hexagon.S2.asl.i.p" => "__builtin_HEXAGON_S2_asl_i_p",
+    "llvm.hexagon.S2.asl.i.p.acc" => "__builtin_HEXAGON_S2_asl_i_p_acc",
+    "llvm.hexagon.S2.asl.i.p.and" => "__builtin_HEXAGON_S2_asl_i_p_and",
+    "llvm.hexagon.S2.asl.i.p.nac" => "__builtin_HEXAGON_S2_asl_i_p_nac",
+    "llvm.hexagon.S2.asl.i.p.or" => "__builtin_HEXAGON_S2_asl_i_p_or",
+    "llvm.hexagon.S2.asl.i.p.xacc" => "__builtin_HEXAGON_S2_asl_i_p_xacc",
+    "llvm.hexagon.S2.asl.i.r" => "__builtin_HEXAGON_S2_asl_i_r",
+    "llvm.hexagon.S2.asl.i.r.acc" => "__builtin_HEXAGON_S2_asl_i_r_acc",
+    "llvm.hexagon.S2.asl.i.r.and" => "__builtin_HEXAGON_S2_asl_i_r_and",
+    "llvm.hexagon.S2.asl.i.r.nac" => "__builtin_HEXAGON_S2_asl_i_r_nac",
+    "llvm.hexagon.S2.asl.i.r.or" => "__builtin_HEXAGON_S2_asl_i_r_or",
+    "llvm.hexagon.S2.asl.i.r.sat" => "__builtin_HEXAGON_S2_asl_i_r_sat",
+    "llvm.hexagon.S2.asl.i.r.xacc" => "__builtin_HEXAGON_S2_asl_i_r_xacc",
+    "llvm.hexagon.S2.asl.i.vh" => "__builtin_HEXAGON_S2_asl_i_vh",
+    "llvm.hexagon.S2.asl.i.vw" => "__builtin_HEXAGON_S2_asl_i_vw",
+    "llvm.hexagon.S2.asl.r.p" => "__builtin_HEXAGON_S2_asl_r_p",
+    "llvm.hexagon.S2.asl.r.p.acc" => "__builtin_HEXAGON_S2_asl_r_p_acc",
+    "llvm.hexagon.S2.asl.r.p.and" => "__builtin_HEXAGON_S2_asl_r_p_and",
+    "llvm.hexagon.S2.asl.r.p.nac" => "__builtin_HEXAGON_S2_asl_r_p_nac",
+    "llvm.hexagon.S2.asl.r.p.or" => "__builtin_HEXAGON_S2_asl_r_p_or",
+    "llvm.hexagon.S2.asl.r.p.xor" => "__builtin_HEXAGON_S2_asl_r_p_xor",
+    "llvm.hexagon.S2.asl.r.r" => "__builtin_HEXAGON_S2_asl_r_r",
+    "llvm.hexagon.S2.asl.r.r.acc" => "__builtin_HEXAGON_S2_asl_r_r_acc",
+    "llvm.hexagon.S2.asl.r.r.and" => "__builtin_HEXAGON_S2_asl_r_r_and",
+    "llvm.hexagon.S2.asl.r.r.nac" => "__builtin_HEXAGON_S2_asl_r_r_nac",
+    "llvm.hexagon.S2.asl.r.r.or" => "__builtin_HEXAGON_S2_asl_r_r_or",
+    "llvm.hexagon.S2.asl.r.r.sat" => "__builtin_HEXAGON_S2_asl_r_r_sat",
+    "llvm.hexagon.S2.asl.r.vh" => "__builtin_HEXAGON_S2_asl_r_vh",
+    "llvm.hexagon.S2.asl.r.vw" => "__builtin_HEXAGON_S2_asl_r_vw",
+    "llvm.hexagon.S2.asr.i.p" => "__builtin_HEXAGON_S2_asr_i_p",
+    "llvm.hexagon.S2.asr.i.p.acc" => "__builtin_HEXAGON_S2_asr_i_p_acc",
+    "llvm.hexagon.S2.asr.i.p.and" => "__builtin_HEXAGON_S2_asr_i_p_and",
+    "llvm.hexagon.S2.asr.i.p.nac" => "__builtin_HEXAGON_S2_asr_i_p_nac",
+    "llvm.hexagon.S2.asr.i.p.or" => "__builtin_HEXAGON_S2_asr_i_p_or",
+    "llvm.hexagon.S2.asr.i.p.rnd" => "__builtin_HEXAGON_S2_asr_i_p_rnd",
+    "llvm.hexagon.S2.asr.i.p.rnd.goodsyntax" => "__builtin_HEXAGON_S2_asr_i_p_rnd_goodsyntax",
+    "llvm.hexagon.S2.asr.i.r" => "__builtin_HEXAGON_S2_asr_i_r",
+    "llvm.hexagon.S2.asr.i.r.acc" => "__builtin_HEXAGON_S2_asr_i_r_acc",
+    "llvm.hexagon.S2.asr.i.r.and" => "__builtin_HEXAGON_S2_asr_i_r_and",
+    "llvm.hexagon.S2.asr.i.r.nac" => "__builtin_HEXAGON_S2_asr_i_r_nac",
+    "llvm.hexagon.S2.asr.i.r.or" => "__builtin_HEXAGON_S2_asr_i_r_or",
+    "llvm.hexagon.S2.asr.i.r.rnd" => "__builtin_HEXAGON_S2_asr_i_r_rnd",
+    "llvm.hexagon.S2.asr.i.r.rnd.goodsyntax" => "__builtin_HEXAGON_S2_asr_i_r_rnd_goodsyntax",
+    "llvm.hexagon.S2.asr.i.svw.trun" => "__builtin_HEXAGON_S2_asr_i_svw_trun",
+    "llvm.hexagon.S2.asr.i.vh" => "__builtin_HEXAGON_S2_asr_i_vh",
+    "llvm.hexagon.S2.asr.i.vw" => "__builtin_HEXAGON_S2_asr_i_vw",
+    "llvm.hexagon.S2.asr.r.p" => "__builtin_HEXAGON_S2_asr_r_p",
+    "llvm.hexagon.S2.asr.r.p.acc" => "__builtin_HEXAGON_S2_asr_r_p_acc",
+    "llvm.hexagon.S2.asr.r.p.and" => "__builtin_HEXAGON_S2_asr_r_p_and",
+    "llvm.hexagon.S2.asr.r.p.nac" => "__builtin_HEXAGON_S2_asr_r_p_nac",
+    "llvm.hexagon.S2.asr.r.p.or" => "__builtin_HEXAGON_S2_asr_r_p_or",
+    "llvm.hexagon.S2.asr.r.p.xor" => "__builtin_HEXAGON_S2_asr_r_p_xor",
+    "llvm.hexagon.S2.asr.r.r" => "__builtin_HEXAGON_S2_asr_r_r",
+    "llvm.hexagon.S2.asr.r.r.acc" => "__builtin_HEXAGON_S2_asr_r_r_acc",
+    "llvm.hexagon.S2.asr.r.r.and" => "__builtin_HEXAGON_S2_asr_r_r_and",
+    "llvm.hexagon.S2.asr.r.r.nac" => "__builtin_HEXAGON_S2_asr_r_r_nac",
+    "llvm.hexagon.S2.asr.r.r.or" => "__builtin_HEXAGON_S2_asr_r_r_or",
+    "llvm.hexagon.S2.asr.r.r.sat" => "__builtin_HEXAGON_S2_asr_r_r_sat",
+    "llvm.hexagon.S2.asr.r.svw.trun" => "__builtin_HEXAGON_S2_asr_r_svw_trun",
+    "llvm.hexagon.S2.asr.r.vh" => "__builtin_HEXAGON_S2_asr_r_vh",
+    "llvm.hexagon.S2.asr.r.vw" => "__builtin_HEXAGON_S2_asr_r_vw",
+    "llvm.hexagon.S2.brev" => "__builtin_HEXAGON_S2_brev",
+    "llvm.hexagon.S2.brevp" => "__builtin_HEXAGON_S2_brevp",
+    "llvm.hexagon.S2.cabacencbin" => "__builtin_HEXAGON_S2_cabacencbin",
+    "llvm.hexagon.S2.cl0" => "__builtin_HEXAGON_S2_cl0",
+    "llvm.hexagon.S2.cl0p" => "__builtin_HEXAGON_S2_cl0p",
+    "llvm.hexagon.S2.cl1" => "__builtin_HEXAGON_S2_cl1",
+    "llvm.hexagon.S2.cl1p" => "__builtin_HEXAGON_S2_cl1p",
+    "llvm.hexagon.S2.clb" => "__builtin_HEXAGON_S2_clb",
+    "llvm.hexagon.S2.clbnorm" => "__builtin_HEXAGON_S2_clbnorm",
+    "llvm.hexagon.S2.clbp" => "__builtin_HEXAGON_S2_clbp",
+    "llvm.hexagon.S2.clrbit.i" => "__builtin_HEXAGON_S2_clrbit_i",
+    "llvm.hexagon.S2.clrbit.r" => "__builtin_HEXAGON_S2_clrbit_r",
+    "llvm.hexagon.S2.ct0" => "__builtin_HEXAGON_S2_ct0",
+    "llvm.hexagon.S2.ct0p" => "__builtin_HEXAGON_S2_ct0p",
+    "llvm.hexagon.S2.ct1" => "__builtin_HEXAGON_S2_ct1",
+    "llvm.hexagon.S2.ct1p" => "__builtin_HEXAGON_S2_ct1p",
+    "llvm.hexagon.S2.deinterleave" => "__builtin_HEXAGON_S2_deinterleave",
+    "llvm.hexagon.S2.extractu" => "__builtin_HEXAGON_S2_extractu",
+    "llvm.hexagon.S2.extractu.rp" => "__builtin_HEXAGON_S2_extractu_rp",
+    "llvm.hexagon.S2.extractup" => "__builtin_HEXAGON_S2_extractup",
+    "llvm.hexagon.S2.extractup.rp" => "__builtin_HEXAGON_S2_extractup_rp",
+    "llvm.hexagon.S2.insert" => "__builtin_HEXAGON_S2_insert",
+    "llvm.hexagon.S2.insert.rp" => "__builtin_HEXAGON_S2_insert_rp",
+    "llvm.hexagon.S2.insertp" => "__builtin_HEXAGON_S2_insertp",
+    "llvm.hexagon.S2.insertp.rp" => "__builtin_HEXAGON_S2_insertp_rp",
+    "llvm.hexagon.S2.interleave" => "__builtin_HEXAGON_S2_interleave",
+    "llvm.hexagon.S2.lfsp" => "__builtin_HEXAGON_S2_lfsp",
+    "llvm.hexagon.S2.lsl.r.p" => "__builtin_HEXAGON_S2_lsl_r_p",
+    "llvm.hexagon.S2.lsl.r.p.acc" => "__builtin_HEXAGON_S2_lsl_r_p_acc",
+    "llvm.hexagon.S2.lsl.r.p.and" => "__builtin_HEXAGON_S2_lsl_r_p_and",
+    "llvm.hexagon.S2.lsl.r.p.nac" => "__builtin_HEXAGON_S2_lsl_r_p_nac",
+    "llvm.hexagon.S2.lsl.r.p.or" => "__builtin_HEXAGON_S2_lsl_r_p_or",
+    "llvm.hexagon.S2.lsl.r.p.xor" => "__builtin_HEXAGON_S2_lsl_r_p_xor",
+    "llvm.hexagon.S2.lsl.r.r" => "__builtin_HEXAGON_S2_lsl_r_r",
+    "llvm.hexagon.S2.lsl.r.r.acc" => "__builtin_HEXAGON_S2_lsl_r_r_acc",
+    "llvm.hexagon.S2.lsl.r.r.and" => "__builtin_HEXAGON_S2_lsl_r_r_and",
+    "llvm.hexagon.S2.lsl.r.r.nac" => "__builtin_HEXAGON_S2_lsl_r_r_nac",
+    "llvm.hexagon.S2.lsl.r.r.or" => "__builtin_HEXAGON_S2_lsl_r_r_or",
+    "llvm.hexagon.S2.lsl.r.vh" => "__builtin_HEXAGON_S2_lsl_r_vh",
+    "llvm.hexagon.S2.lsl.r.vw" => "__builtin_HEXAGON_S2_lsl_r_vw",
+    "llvm.hexagon.S2.lsr.i.p" => "__builtin_HEXAGON_S2_lsr_i_p",
+    "llvm.hexagon.S2.lsr.i.p.acc" => "__builtin_HEXAGON_S2_lsr_i_p_acc",
+    "llvm.hexagon.S2.lsr.i.p.and" => "__builtin_HEXAGON_S2_lsr_i_p_and",
+    "llvm.hexagon.S2.lsr.i.p.nac" => "__builtin_HEXAGON_S2_lsr_i_p_nac",
+    "llvm.hexagon.S2.lsr.i.p.or" => "__builtin_HEXAGON_S2_lsr_i_p_or",
+    "llvm.hexagon.S2.lsr.i.p.xacc" => "__builtin_HEXAGON_S2_lsr_i_p_xacc",
+    "llvm.hexagon.S2.lsr.i.r" => "__builtin_HEXAGON_S2_lsr_i_r",
+    "llvm.hexagon.S2.lsr.i.r.acc" => "__builtin_HEXAGON_S2_lsr_i_r_acc",
+    "llvm.hexagon.S2.lsr.i.r.and" => "__builtin_HEXAGON_S2_lsr_i_r_and",
+    "llvm.hexagon.S2.lsr.i.r.nac" => "__builtin_HEXAGON_S2_lsr_i_r_nac",
+    "llvm.hexagon.S2.lsr.i.r.or" => "__builtin_HEXAGON_S2_lsr_i_r_or",
+    "llvm.hexagon.S2.lsr.i.r.xacc" => "__builtin_HEXAGON_S2_lsr_i_r_xacc",
+    "llvm.hexagon.S2.lsr.i.vh" => "__builtin_HEXAGON_S2_lsr_i_vh",
+    "llvm.hexagon.S2.lsr.i.vw" => "__builtin_HEXAGON_S2_lsr_i_vw",
+    "llvm.hexagon.S2.lsr.r.p" => "__builtin_HEXAGON_S2_lsr_r_p",
+    "llvm.hexagon.S2.lsr.r.p.acc" => "__builtin_HEXAGON_S2_lsr_r_p_acc",
+    "llvm.hexagon.S2.lsr.r.p.and" => "__builtin_HEXAGON_S2_lsr_r_p_and",
+    "llvm.hexagon.S2.lsr.r.p.nac" => "__builtin_HEXAGON_S2_lsr_r_p_nac",
+    "llvm.hexagon.S2.lsr.r.p.or" => "__builtin_HEXAGON_S2_lsr_r_p_or",
+    "llvm.hexagon.S2.lsr.r.p.xor" => "__builtin_HEXAGON_S2_lsr_r_p_xor",
+    "llvm.hexagon.S2.lsr.r.r" => "__builtin_HEXAGON_S2_lsr_r_r",
+    "llvm.hexagon.S2.lsr.r.r.acc" => "__builtin_HEXAGON_S2_lsr_r_r_acc",
+    "llvm.hexagon.S2.lsr.r.r.and" => "__builtin_HEXAGON_S2_lsr_r_r_and",
+    "llvm.hexagon.S2.lsr.r.r.nac" => "__builtin_HEXAGON_S2_lsr_r_r_nac",
+    "llvm.hexagon.S2.lsr.r.r.or" => "__builtin_HEXAGON_S2_lsr_r_r_or",
+    "llvm.hexagon.S2.lsr.r.vh" => "__builtin_HEXAGON_S2_lsr_r_vh",
+    "llvm.hexagon.S2.lsr.r.vw" => "__builtin_HEXAGON_S2_lsr_r_vw",
+    "llvm.hexagon.S2.packhl" => "__builtin_HEXAGON_S2_packhl",
+    "llvm.hexagon.S2.parityp" => "__builtin_HEXAGON_S2_parityp",
+    "llvm.hexagon.S2.setbit.i" => "__builtin_HEXAGON_S2_setbit_i",
+    "llvm.hexagon.S2.setbit.r" => "__builtin_HEXAGON_S2_setbit_r",
+    "llvm.hexagon.S2.shuffeb" => "__builtin_HEXAGON_S2_shuffeb",
+    "llvm.hexagon.S2.shuffeh" => "__builtin_HEXAGON_S2_shuffeh",
+    "llvm.hexagon.S2.shuffob" => "__builtin_HEXAGON_S2_shuffob",
+    "llvm.hexagon.S2.shuffoh" => "__builtin_HEXAGON_S2_shuffoh",
+    "llvm.hexagon.S2.svsathb" => "__builtin_HEXAGON_S2_svsathb",
+    "llvm.hexagon.S2.svsathub" => "__builtin_HEXAGON_S2_svsathub",
+    "llvm.hexagon.S2.tableidxb.goodsyntax" => "__builtin_HEXAGON_S2_tableidxb_goodsyntax",
+    "llvm.hexagon.S2.tableidxd.goodsyntax" => "__builtin_HEXAGON_S2_tableidxd_goodsyntax",
+    "llvm.hexagon.S2.tableidxh.goodsyntax" => "__builtin_HEXAGON_S2_tableidxh_goodsyntax",
+    "llvm.hexagon.S2.tableidxw.goodsyntax" => "__builtin_HEXAGON_S2_tableidxw_goodsyntax",
+    "llvm.hexagon.S2.togglebit.i" => "__builtin_HEXAGON_S2_togglebit_i",
+    "llvm.hexagon.S2.togglebit.r" => "__builtin_HEXAGON_S2_togglebit_r",
+    "llvm.hexagon.S2.tstbit.i" => "__builtin_HEXAGON_S2_tstbit_i",
+    "llvm.hexagon.S2.tstbit.r" => "__builtin_HEXAGON_S2_tstbit_r",
+    "llvm.hexagon.S2.valignib" => "__builtin_HEXAGON_S2_valignib",
+    "llvm.hexagon.S2.valignrb" => "__builtin_HEXAGON_S2_valignrb",
+    "llvm.hexagon.S2.vcnegh" => "__builtin_HEXAGON_S2_vcnegh",
+    "llvm.hexagon.S2.vcrotate" => "__builtin_HEXAGON_S2_vcrotate",
+    "llvm.hexagon.S2.vrcnegh" => "__builtin_HEXAGON_S2_vrcnegh",
+    "llvm.hexagon.S2.vrndpackwh" => "__builtin_HEXAGON_S2_vrndpackwh",
+    "llvm.hexagon.S2.vrndpackwhs" => "__builtin_HEXAGON_S2_vrndpackwhs",
+    "llvm.hexagon.S2.vsathb" => "__builtin_HEXAGON_S2_vsathb",
+    "llvm.hexagon.S2.vsathb.nopack" => "__builtin_HEXAGON_S2_vsathb_nopack",
+    "llvm.hexagon.S2.vsathub" => "__builtin_HEXAGON_S2_vsathub",
+    "llvm.hexagon.S2.vsathub.nopack" => "__builtin_HEXAGON_S2_vsathub_nopack",
+    "llvm.hexagon.S2.vsatwh" => "__builtin_HEXAGON_S2_vsatwh",
+    "llvm.hexagon.S2.vsatwh.nopack" => "__builtin_HEXAGON_S2_vsatwh_nopack",
+    "llvm.hexagon.S2.vsatwuh" => "__builtin_HEXAGON_S2_vsatwuh",
+    "llvm.hexagon.S2.vsatwuh.nopack" => "__builtin_HEXAGON_S2_vsatwuh_nopack",
+    "llvm.hexagon.S2.vsplatrb" => "__builtin_HEXAGON_S2_vsplatrb",
+    "llvm.hexagon.S2.vsplatrh" => "__builtin_HEXAGON_S2_vsplatrh",
+    "llvm.hexagon.S2.vspliceib" => "__builtin_HEXAGON_S2_vspliceib",
+    "llvm.hexagon.S2.vsplicerb" => "__builtin_HEXAGON_S2_vsplicerb",
+    "llvm.hexagon.S2.vsxtbh" => "__builtin_HEXAGON_S2_vsxtbh",
+    "llvm.hexagon.S2.vsxthw" => "__builtin_HEXAGON_S2_vsxthw",
+    "llvm.hexagon.S2.vtrunehb" => "__builtin_HEXAGON_S2_vtrunehb",
+    "llvm.hexagon.S2.vtrunewh" => "__builtin_HEXAGON_S2_vtrunewh",
+    "llvm.hexagon.S2.vtrunohb" => "__builtin_HEXAGON_S2_vtrunohb",
+    "llvm.hexagon.S2.vtrunowh" => "__builtin_HEXAGON_S2_vtrunowh",
+    "llvm.hexagon.S2.vzxtbh" => "__builtin_HEXAGON_S2_vzxtbh",
+    "llvm.hexagon.S2.vzxthw" => "__builtin_HEXAGON_S2_vzxthw",
+    "llvm.hexagon.S4.addaddi" => "__builtin_HEXAGON_S4_addaddi",
+    "llvm.hexagon.S4.addi.asl.ri" => "__builtin_HEXAGON_S4_addi_asl_ri",
+    "llvm.hexagon.S4.addi.lsr.ri" => "__builtin_HEXAGON_S4_addi_lsr_ri",
+    "llvm.hexagon.S4.andi.asl.ri" => "__builtin_HEXAGON_S4_andi_asl_ri",
+    "llvm.hexagon.S4.andi.lsr.ri" => "__builtin_HEXAGON_S4_andi_lsr_ri",
+    "llvm.hexagon.S4.clbaddi" => "__builtin_HEXAGON_S4_clbaddi",
+    "llvm.hexagon.S4.clbpaddi" => "__builtin_HEXAGON_S4_clbpaddi",
+    "llvm.hexagon.S4.clbpnorm" => "__builtin_HEXAGON_S4_clbpnorm",
+    "llvm.hexagon.S4.extract" => "__builtin_HEXAGON_S4_extract",
+    "llvm.hexagon.S4.extract.rp" => "__builtin_HEXAGON_S4_extract_rp",
+    "llvm.hexagon.S4.extractp" => "__builtin_HEXAGON_S4_extractp",
+    "llvm.hexagon.S4.extractp.rp" => "__builtin_HEXAGON_S4_extractp_rp",
+    "llvm.hexagon.S4.lsli" => "__builtin_HEXAGON_S4_lsli",
+    "llvm.hexagon.S4.ntstbit.i" => "__builtin_HEXAGON_S4_ntstbit_i",
+    "llvm.hexagon.S4.ntstbit.r" => "__builtin_HEXAGON_S4_ntstbit_r",
+    "llvm.hexagon.S4.or.andi" => "__builtin_HEXAGON_S4_or_andi",
+    "llvm.hexagon.S4.or.andix" => "__builtin_HEXAGON_S4_or_andix",
+    "llvm.hexagon.S4.or.ori" => "__builtin_HEXAGON_S4_or_ori",
+    "llvm.hexagon.S4.ori.asl.ri" => "__builtin_HEXAGON_S4_ori_asl_ri",
+    "llvm.hexagon.S4.ori.lsr.ri" => "__builtin_HEXAGON_S4_ori_lsr_ri",
+    "llvm.hexagon.S4.parity" => "__builtin_HEXAGON_S4_parity",
+    "llvm.hexagon.S4.subaddi" => "__builtin_HEXAGON_S4_subaddi",
+    "llvm.hexagon.S4.subi.asl.ri" => "__builtin_HEXAGON_S4_subi_asl_ri",
+    "llvm.hexagon.S4.subi.lsr.ri" => "__builtin_HEXAGON_S4_subi_lsr_ri",
+    "llvm.hexagon.S4.vrcrotate" => "__builtin_HEXAGON_S4_vrcrotate",
+    "llvm.hexagon.S4.vrcrotate.acc" => "__builtin_HEXAGON_S4_vrcrotate_acc",
+    "llvm.hexagon.S4.vxaddsubh" => "__builtin_HEXAGON_S4_vxaddsubh",
+    "llvm.hexagon.S4.vxaddsubhr" => "__builtin_HEXAGON_S4_vxaddsubhr",
+    "llvm.hexagon.S4.vxaddsubw" => "__builtin_HEXAGON_S4_vxaddsubw",
+    "llvm.hexagon.S4.vxsubaddh" => "__builtin_HEXAGON_S4_vxsubaddh",
+    "llvm.hexagon.S4.vxsubaddhr" => "__builtin_HEXAGON_S4_vxsubaddhr",
+    "llvm.hexagon.S4.vxsubaddw" => "__builtin_HEXAGON_S4_vxsubaddw",
+    "llvm.hexagon.S5.asrhub.rnd.sat.goodsyntax" => "__builtin_HEXAGON_S5_asrhub_rnd_sat_goodsyntax",
+    "llvm.hexagon.S5.asrhub.sat" => "__builtin_HEXAGON_S5_asrhub_sat",
+    "llvm.hexagon.S5.popcountp" => "__builtin_HEXAGON_S5_popcountp",
+    "llvm.hexagon.S5.vasrhrnd.goodsyntax" => "__builtin_HEXAGON_S5_vasrhrnd_goodsyntax",
+    "llvm.hexagon.S6.rol.i.p" => "__builtin_HEXAGON_S6_rol_i_p",
+    "llvm.hexagon.S6.rol.i.p.acc" => "__builtin_HEXAGON_S6_rol_i_p_acc",
+    "llvm.hexagon.S6.rol.i.p.and" => "__builtin_HEXAGON_S6_rol_i_p_and",
+    "llvm.hexagon.S6.rol.i.p.nac" => "__builtin_HEXAGON_S6_rol_i_p_nac",
+    "llvm.hexagon.S6.rol.i.p.or" => "__builtin_HEXAGON_S6_rol_i_p_or",
+    "llvm.hexagon.S6.rol.i.p.xacc" => "__builtin_HEXAGON_S6_rol_i_p_xacc",
+    "llvm.hexagon.S6.rol.i.r" => "__builtin_HEXAGON_S6_rol_i_r",
+    "llvm.hexagon.S6.rol.i.r.acc" => "__builtin_HEXAGON_S6_rol_i_r_acc",
+    "llvm.hexagon.S6.rol.i.r.and" => "__builtin_HEXAGON_S6_rol_i_r_and",
+    "llvm.hexagon.S6.rol.i.r.nac" => "__builtin_HEXAGON_S6_rol_i_r_nac",
+    "llvm.hexagon.S6.rol.i.r.or" => "__builtin_HEXAGON_S6_rol_i_r_or",
+    "llvm.hexagon.S6.rol.i.r.xacc" => "__builtin_HEXAGON_S6_rol_i_r_xacc",
+    "llvm.hexagon.S6.vsplatrbp" => "__builtin_HEXAGON_S6_vsplatrbp",
+    "llvm.hexagon.S6.vtrunehb.ppp" => "__builtin_HEXAGON_S6_vtrunehb_ppp",
+    "llvm.hexagon.S6.vtrunohb.ppp" => "__builtin_HEXAGON_S6_vtrunohb_ppp",
+    "llvm.hexagon.SI.to.SXTHI.asrh" => "__builtin_SI_to_SXTHI_asrh",
+    "llvm.hexagon.V6.extractw" => "__builtin_HEXAGON_V6_extractw",
+    "llvm.hexagon.V6.extractw.128B" => "__builtin_HEXAGON_V6_extractw_128B",
+    "llvm.hexagon.V6.hi" => "__builtin_HEXAGON_V6_hi",
+    "llvm.hexagon.V6.hi.128B" => "__builtin_HEXAGON_V6_hi_128B",
+    "llvm.hexagon.V6.lo" => "__builtin_HEXAGON_V6_lo",
+    "llvm.hexagon.V6.lo.128B" => "__builtin_HEXAGON_V6_lo_128B",
+    "llvm.hexagon.V6.lvsplatw" => "__builtin_HEXAGON_V6_lvsplatw",
+    "llvm.hexagon.V6.lvsplatw.128B" => "__builtin_HEXAGON_V6_lvsplatw_128B",
+    "llvm.hexagon.V6.vabsdiffh" => "__builtin_HEXAGON_V6_vabsdiffh",
+    "llvm.hexagon.V6.vabsdiffh.128B" => "__builtin_HEXAGON_V6_vabsdiffh_128B",
+    "llvm.hexagon.V6.vabsdiffub" => "__builtin_HEXAGON_V6_vabsdiffub",
+    "llvm.hexagon.V6.vabsdiffub.128B" => "__builtin_HEXAGON_V6_vabsdiffub_128B",
+    "llvm.hexagon.V6.vabsdiffuh" => "__builtin_HEXAGON_V6_vabsdiffuh",
+    "llvm.hexagon.V6.vabsdiffuh.128B" => "__builtin_HEXAGON_V6_vabsdiffuh_128B",
+    "llvm.hexagon.V6.vabsdiffw" => "__builtin_HEXAGON_V6_vabsdiffw",
+    "llvm.hexagon.V6.vabsdiffw.128B" => "__builtin_HEXAGON_V6_vabsdiffw_128B",
+    "llvm.hexagon.V6.vabsh" => "__builtin_HEXAGON_V6_vabsh",
+    "llvm.hexagon.V6.vabsh.128B" => "__builtin_HEXAGON_V6_vabsh_128B",
+    "llvm.hexagon.V6.vabsh.sat" => "__builtin_HEXAGON_V6_vabsh_sat",
+    "llvm.hexagon.V6.vabsh.sat.128B" => "__builtin_HEXAGON_V6_vabsh_sat_128B",
+    "llvm.hexagon.V6.vabsw" => "__builtin_HEXAGON_V6_vabsw",
+    "llvm.hexagon.V6.vabsw.128B" => "__builtin_HEXAGON_V6_vabsw_128B",
+    "llvm.hexagon.V6.vabsw.sat" => "__builtin_HEXAGON_V6_vabsw_sat",
+    "llvm.hexagon.V6.vabsw.sat.128B" => "__builtin_HEXAGON_V6_vabsw_sat_128B",
+    "llvm.hexagon.V6.vaddb" => "__builtin_HEXAGON_V6_vaddb",
+    "llvm.hexagon.V6.vaddb.128B" => "__builtin_HEXAGON_V6_vaddb_128B",
+    "llvm.hexagon.V6.vaddb.dv" => "__builtin_HEXAGON_V6_vaddb_dv",
+    "llvm.hexagon.V6.vaddb.dv.128B" => "__builtin_HEXAGON_V6_vaddb_dv_128B",
+    "llvm.hexagon.V6.vaddh" => "__builtin_HEXAGON_V6_vaddh",
+    "llvm.hexagon.V6.vaddh.128B" => "__builtin_HEXAGON_V6_vaddh_128B",
+    "llvm.hexagon.V6.vaddh.dv" => "__builtin_HEXAGON_V6_vaddh_dv",
+    "llvm.hexagon.V6.vaddh.dv.128B" => "__builtin_HEXAGON_V6_vaddh_dv_128B",
+    "llvm.hexagon.V6.vaddhsat" => "__builtin_HEXAGON_V6_vaddhsat",
+    "llvm.hexagon.V6.vaddhsat.128B" => "__builtin_HEXAGON_V6_vaddhsat_128B",
+    "llvm.hexagon.V6.vaddhsat.dv" => "__builtin_HEXAGON_V6_vaddhsat_dv",
+    "llvm.hexagon.V6.vaddhsat.dv.128B" => "__builtin_HEXAGON_V6_vaddhsat_dv_128B",
+    "llvm.hexagon.V6.vaddhw" => "__builtin_HEXAGON_V6_vaddhw",
+    "llvm.hexagon.V6.vaddhw.128B" => "__builtin_HEXAGON_V6_vaddhw_128B",
+    "llvm.hexagon.V6.vaddubh" => "__builtin_HEXAGON_V6_vaddubh",
+    "llvm.hexagon.V6.vaddubh.128B" => "__builtin_HEXAGON_V6_vaddubh_128B",
+    "llvm.hexagon.V6.vaddubsat" => "__builtin_HEXAGON_V6_vaddubsat",
+    "llvm.hexagon.V6.vaddubsat.128B" => "__builtin_HEXAGON_V6_vaddubsat_128B",
+    "llvm.hexagon.V6.vaddubsat.dv" => "__builtin_HEXAGON_V6_vaddubsat_dv",
+    "llvm.hexagon.V6.vaddubsat.dv.128B" => "__builtin_HEXAGON_V6_vaddubsat_dv_128B",
+    "llvm.hexagon.V6.vadduhsat" => "__builtin_HEXAGON_V6_vadduhsat",
+    "llvm.hexagon.V6.vadduhsat.128B" => "__builtin_HEXAGON_V6_vadduhsat_128B",
+    "llvm.hexagon.V6.vadduhsat.dv" => "__builtin_HEXAGON_V6_vadduhsat_dv",
+    "llvm.hexagon.V6.vadduhsat.dv.128B" => "__builtin_HEXAGON_V6_vadduhsat_dv_128B",
+    "llvm.hexagon.V6.vadduhw" => "__builtin_HEXAGON_V6_vadduhw",
+    "llvm.hexagon.V6.vadduhw.128B" => "__builtin_HEXAGON_V6_vadduhw_128B",
+    "llvm.hexagon.V6.vaddw" => "__builtin_HEXAGON_V6_vaddw",
+    "llvm.hexagon.V6.vaddw.128B" => "__builtin_HEXAGON_V6_vaddw_128B",
+    "llvm.hexagon.V6.vaddw.dv" => "__builtin_HEXAGON_V6_vaddw_dv",
+    "llvm.hexagon.V6.vaddw.dv.128B" => "__builtin_HEXAGON_V6_vaddw_dv_128B",
+    "llvm.hexagon.V6.vaddwsat" => "__builtin_HEXAGON_V6_vaddwsat",
+    "llvm.hexagon.V6.vaddwsat.128B" => "__builtin_HEXAGON_V6_vaddwsat_128B",
+    "llvm.hexagon.V6.vaddwsat.dv" => "__builtin_HEXAGON_V6_vaddwsat_dv",
+    "llvm.hexagon.V6.vaddwsat.dv.128B" => "__builtin_HEXAGON_V6_vaddwsat_dv_128B",
+    "llvm.hexagon.V6.valignb" => "__builtin_HEXAGON_V6_valignb",
+    "llvm.hexagon.V6.valignb.128B" => "__builtin_HEXAGON_V6_valignb_128B",
+    "llvm.hexagon.V6.valignbi" => "__builtin_HEXAGON_V6_valignbi",
+    "llvm.hexagon.V6.valignbi.128B" => "__builtin_HEXAGON_V6_valignbi_128B",
+    "llvm.hexagon.V6.vand" => "__builtin_HEXAGON_V6_vand",
+    "llvm.hexagon.V6.vand.128B" => "__builtin_HEXAGON_V6_vand_128B",
+    "llvm.hexagon.V6.vaslh" => "__builtin_HEXAGON_V6_vaslh",
+    "llvm.hexagon.V6.vaslh.128B" => "__builtin_HEXAGON_V6_vaslh_128B",
+    "llvm.hexagon.V6.vaslhv" => "__builtin_HEXAGON_V6_vaslhv",
+    "llvm.hexagon.V6.vaslhv.128B" => "__builtin_HEXAGON_V6_vaslhv_128B",
+    "llvm.hexagon.V6.vaslw" => "__builtin_HEXAGON_V6_vaslw",
+    "llvm.hexagon.V6.vaslw.128B" => "__builtin_HEXAGON_V6_vaslw_128B",
+    "llvm.hexagon.V6.vaslw.acc" => "__builtin_HEXAGON_V6_vaslw_acc",
+    "llvm.hexagon.V6.vaslw.acc.128B" => "__builtin_HEXAGON_V6_vaslw_acc_128B",
+    "llvm.hexagon.V6.vaslwv" => "__builtin_HEXAGON_V6_vaslwv",
+    "llvm.hexagon.V6.vaslwv.128B" => "__builtin_HEXAGON_V6_vaslwv_128B",
+    "llvm.hexagon.V6.vasrh" => "__builtin_HEXAGON_V6_vasrh",
+    "llvm.hexagon.V6.vasrh.128B" => "__builtin_HEXAGON_V6_vasrh_128B",
+    "llvm.hexagon.V6.vasrhbrndsat" => "__builtin_HEXAGON_V6_vasrhbrndsat",
+    "llvm.hexagon.V6.vasrhbrndsat.128B" => "__builtin_HEXAGON_V6_vasrhbrndsat_128B",
+    "llvm.hexagon.V6.vasrhubrndsat" => "__builtin_HEXAGON_V6_vasrhubrndsat",
+    "llvm.hexagon.V6.vasrhubrndsat.128B" => "__builtin_HEXAGON_V6_vasrhubrndsat_128B",
+    "llvm.hexagon.V6.vasrhubsat" => "__builtin_HEXAGON_V6_vasrhubsat",
+    "llvm.hexagon.V6.vasrhubsat.128B" => "__builtin_HEXAGON_V6_vasrhubsat_128B",
+    "llvm.hexagon.V6.vasrhv" => "__builtin_HEXAGON_V6_vasrhv",
+    "llvm.hexagon.V6.vasrhv.128B" => "__builtin_HEXAGON_V6_vasrhv_128B",
+    "llvm.hexagon.V6.vasrw" => "__builtin_HEXAGON_V6_vasrw",
+    "llvm.hexagon.V6.vasrw.128B" => "__builtin_HEXAGON_V6_vasrw_128B",
+    "llvm.hexagon.V6.vasrw.acc" => "__builtin_HEXAGON_V6_vasrw_acc",
+    "llvm.hexagon.V6.vasrw.acc.128B" => "__builtin_HEXAGON_V6_vasrw_acc_128B",
+    "llvm.hexagon.V6.vasrwh" => "__builtin_HEXAGON_V6_vasrwh",
+    "llvm.hexagon.V6.vasrwh.128B" => "__builtin_HEXAGON_V6_vasrwh_128B",
+    "llvm.hexagon.V6.vasrwhrndsat" => "__builtin_HEXAGON_V6_vasrwhrndsat",
+    "llvm.hexagon.V6.vasrwhrndsat.128B" => "__builtin_HEXAGON_V6_vasrwhrndsat_128B",
+    "llvm.hexagon.V6.vasrwhsat" => "__builtin_HEXAGON_V6_vasrwhsat",
+    "llvm.hexagon.V6.vasrwhsat.128B" => "__builtin_HEXAGON_V6_vasrwhsat_128B",
+    "llvm.hexagon.V6.vasrwuhsat" => "__builtin_HEXAGON_V6_vasrwuhsat",
+    "llvm.hexagon.V6.vasrwuhsat.128B" => "__builtin_HEXAGON_V6_vasrwuhsat_128B",
+    "llvm.hexagon.V6.vasrwv" => "__builtin_HEXAGON_V6_vasrwv",
+    "llvm.hexagon.V6.vasrwv.128B" => "__builtin_HEXAGON_V6_vasrwv_128B",
+    "llvm.hexagon.V6.vassign" => "__builtin_HEXAGON_V6_vassign",
+    "llvm.hexagon.V6.vassign.128B" => "__builtin_HEXAGON_V6_vassign_128B",
+    "llvm.hexagon.V6.vassignp" => "__builtin_HEXAGON_V6_vassignp",
+    "llvm.hexagon.V6.vassignp.128B" => "__builtin_HEXAGON_V6_vassignp_128B",
+    "llvm.hexagon.V6.vavgh" => "__builtin_HEXAGON_V6_vavgh",
+    "llvm.hexagon.V6.vavgh.128B" => "__builtin_HEXAGON_V6_vavgh_128B",
+    "llvm.hexagon.V6.vavghrnd" => "__builtin_HEXAGON_V6_vavghrnd",
+    "llvm.hexagon.V6.vavghrnd.128B" => "__builtin_HEXAGON_V6_vavghrnd_128B",
+    "llvm.hexagon.V6.vavgub" => "__builtin_HEXAGON_V6_vavgub",
+    "llvm.hexagon.V6.vavgub.128B" => "__builtin_HEXAGON_V6_vavgub_128B",
+    "llvm.hexagon.V6.vavgubrnd" => "__builtin_HEXAGON_V6_vavgubrnd",
+    "llvm.hexagon.V6.vavgubrnd.128B" => "__builtin_HEXAGON_V6_vavgubrnd_128B",
+    "llvm.hexagon.V6.vavguh" => "__builtin_HEXAGON_V6_vavguh",
+    "llvm.hexagon.V6.vavguh.128B" => "__builtin_HEXAGON_V6_vavguh_128B",
+    "llvm.hexagon.V6.vavguhrnd" => "__builtin_HEXAGON_V6_vavguhrnd",
+    "llvm.hexagon.V6.vavguhrnd.128B" => "__builtin_HEXAGON_V6_vavguhrnd_128B",
+    "llvm.hexagon.V6.vavgw" => "__builtin_HEXAGON_V6_vavgw",
+    "llvm.hexagon.V6.vavgw.128B" => "__builtin_HEXAGON_V6_vavgw_128B",
+    "llvm.hexagon.V6.vavgwrnd" => "__builtin_HEXAGON_V6_vavgwrnd",
+    "llvm.hexagon.V6.vavgwrnd.128B" => "__builtin_HEXAGON_V6_vavgwrnd_128B",
+    "llvm.hexagon.V6.vcl0h" => "__builtin_HEXAGON_V6_vcl0h",
+    "llvm.hexagon.V6.vcl0h.128B" => "__builtin_HEXAGON_V6_vcl0h_128B",
+    "llvm.hexagon.V6.vcl0w" => "__builtin_HEXAGON_V6_vcl0w",
+    "llvm.hexagon.V6.vcl0w.128B" => "__builtin_HEXAGON_V6_vcl0w_128B",
+    "llvm.hexagon.V6.vcombine" => "__builtin_HEXAGON_V6_vcombine",
+    "llvm.hexagon.V6.vcombine.128B" => "__builtin_HEXAGON_V6_vcombine_128B",
+    "llvm.hexagon.V6.vd0" => "__builtin_HEXAGON_V6_vd0",
+    "llvm.hexagon.V6.vd0.128B" => "__builtin_HEXAGON_V6_vd0_128B",
+    "llvm.hexagon.V6.vdealb" => "__builtin_HEXAGON_V6_vdealb",
+    "llvm.hexagon.V6.vdealb.128B" => "__builtin_HEXAGON_V6_vdealb_128B",
+    "llvm.hexagon.V6.vdealb4w" => "__builtin_HEXAGON_V6_vdealb4w",
+    "llvm.hexagon.V6.vdealb4w.128B" => "__builtin_HEXAGON_V6_vdealb4w_128B",
+    "llvm.hexagon.V6.vdealh" => "__builtin_HEXAGON_V6_vdealh",
+    "llvm.hexagon.V6.vdealh.128B" => "__builtin_HEXAGON_V6_vdealh_128B",
+    "llvm.hexagon.V6.vdealvdd" => "__builtin_HEXAGON_V6_vdealvdd",
+    "llvm.hexagon.V6.vdealvdd.128B" => "__builtin_HEXAGON_V6_vdealvdd_128B",
+    "llvm.hexagon.V6.vdelta" => "__builtin_HEXAGON_V6_vdelta",
+    "llvm.hexagon.V6.vdelta.128B" => "__builtin_HEXAGON_V6_vdelta_128B",
+    "llvm.hexagon.V6.vdmpybus" => "__builtin_HEXAGON_V6_vdmpybus",
+    "llvm.hexagon.V6.vdmpybus.128B" => "__builtin_HEXAGON_V6_vdmpybus_128B",
+    "llvm.hexagon.V6.vdmpybus.acc" => "__builtin_HEXAGON_V6_vdmpybus_acc",
+    "llvm.hexagon.V6.vdmpybus.acc.128B" => "__builtin_HEXAGON_V6_vdmpybus_acc_128B",
+    "llvm.hexagon.V6.vdmpybus.dv" => "__builtin_HEXAGON_V6_vdmpybus_dv",
+    "llvm.hexagon.V6.vdmpybus.dv.128B" => "__builtin_HEXAGON_V6_vdmpybus_dv_128B",
+    "llvm.hexagon.V6.vdmpybus.dv.acc" => "__builtin_HEXAGON_V6_vdmpybus_dv_acc",
+    "llvm.hexagon.V6.vdmpybus.dv.acc.128B" => "__builtin_HEXAGON_V6_vdmpybus_dv_acc_128B",
+    "llvm.hexagon.V6.vdmpyhb" => "__builtin_HEXAGON_V6_vdmpyhb",
+    "llvm.hexagon.V6.vdmpyhb.128B" => "__builtin_HEXAGON_V6_vdmpyhb_128B",
+    "llvm.hexagon.V6.vdmpyhb.acc" => "__builtin_HEXAGON_V6_vdmpyhb_acc",
+    "llvm.hexagon.V6.vdmpyhb.acc.128B" => "__builtin_HEXAGON_V6_vdmpyhb_acc_128B",
+    "llvm.hexagon.V6.vdmpyhb.dv" => "__builtin_HEXAGON_V6_vdmpyhb_dv",
+    "llvm.hexagon.V6.vdmpyhb.dv.128B" => "__builtin_HEXAGON_V6_vdmpyhb_dv_128B",
+    "llvm.hexagon.V6.vdmpyhb.dv.acc" => "__builtin_HEXAGON_V6_vdmpyhb_dv_acc",
+    "llvm.hexagon.V6.vdmpyhb.dv.acc.128B" => "__builtin_HEXAGON_V6_vdmpyhb_dv_acc_128B",
+    "llvm.hexagon.V6.vdmpyhisat" => "__builtin_HEXAGON_V6_vdmpyhisat",
+    "llvm.hexagon.V6.vdmpyhisat.128B" => "__builtin_HEXAGON_V6_vdmpyhisat_128B",
+    "llvm.hexagon.V6.vdmpyhisat.acc" => "__builtin_HEXAGON_V6_vdmpyhisat_acc",
+    "llvm.hexagon.V6.vdmpyhisat.acc.128B" => "__builtin_HEXAGON_V6_vdmpyhisat_acc_128B",
+    "llvm.hexagon.V6.vdmpyhsat" => "__builtin_HEXAGON_V6_vdmpyhsat",
+    "llvm.hexagon.V6.vdmpyhsat.128B" => "__builtin_HEXAGON_V6_vdmpyhsat_128B",
+    "llvm.hexagon.V6.vdmpyhsat.acc" => "__builtin_HEXAGON_V6_vdmpyhsat_acc",
+    "llvm.hexagon.V6.vdmpyhsat.acc.128B" => "__builtin_HEXAGON_V6_vdmpyhsat_acc_128B",
+    "llvm.hexagon.V6.vdmpyhsuisat" => "__builtin_HEXAGON_V6_vdmpyhsuisat",
+    "llvm.hexagon.V6.vdmpyhsuisat.128B" => "__builtin_HEXAGON_V6_vdmpyhsuisat_128B",
+    "llvm.hexagon.V6.vdmpyhsuisat.acc" => "__builtin_HEXAGON_V6_vdmpyhsuisat_acc",
+    "llvm.hexagon.V6.vdmpyhsuisat.acc.128B" => "__builtin_HEXAGON_V6_vdmpyhsuisat_acc_128B",
+    "llvm.hexagon.V6.vdmpyhsusat" => "__builtin_HEXAGON_V6_vdmpyhsusat",
+    "llvm.hexagon.V6.vdmpyhsusat.128B" => "__builtin_HEXAGON_V6_vdmpyhsusat_128B",
+    "llvm.hexagon.V6.vdmpyhsusat.acc" => "__builtin_HEXAGON_V6_vdmpyhsusat_acc",
+    "llvm.hexagon.V6.vdmpyhsusat.acc.128B" => "__builtin_HEXAGON_V6_vdmpyhsusat_acc_128B",
+    "llvm.hexagon.V6.vdmpyhvsat" => "__builtin_HEXAGON_V6_vdmpyhvsat",
+    "llvm.hexagon.V6.vdmpyhvsat.128B" => "__builtin_HEXAGON_V6_vdmpyhvsat_128B",
+    "llvm.hexagon.V6.vdmpyhvsat.acc" => "__builtin_HEXAGON_V6_vdmpyhvsat_acc",
+    "llvm.hexagon.V6.vdmpyhvsat.acc.128B" => "__builtin_HEXAGON_V6_vdmpyhvsat_acc_128B",
+    "llvm.hexagon.V6.vdsaduh" => "__builtin_HEXAGON_V6_vdsaduh",
+    "llvm.hexagon.V6.vdsaduh.128B" => "__builtin_HEXAGON_V6_vdsaduh_128B",
+    "llvm.hexagon.V6.vdsaduh.acc" => "__builtin_HEXAGON_V6_vdsaduh_acc",
+    "llvm.hexagon.V6.vdsaduh.acc.128B" => "__builtin_HEXAGON_V6_vdsaduh_acc_128B",
+    "llvm.hexagon.V6.vinsertwr" => "__builtin_HEXAGON_V6_vinsertwr",
+    "llvm.hexagon.V6.vinsertwr.128B" => "__builtin_HEXAGON_V6_vinsertwr_128B",
+    "llvm.hexagon.V6.vlalignb" => "__builtin_HEXAGON_V6_vlalignb",
+    "llvm.hexagon.V6.vlalignb.128B" => "__builtin_HEXAGON_V6_vlalignb_128B",
+    "llvm.hexagon.V6.vlalignbi" => "__builtin_HEXAGON_V6_vlalignbi",
+    "llvm.hexagon.V6.vlalignbi.128B" => "__builtin_HEXAGON_V6_vlalignbi_128B",
+    "llvm.hexagon.V6.vlsrh" => "__builtin_HEXAGON_V6_vlsrh",
+    "llvm.hexagon.V6.vlsrh.128B" => "__builtin_HEXAGON_V6_vlsrh_128B",
+    "llvm.hexagon.V6.vlsrhv" => "__builtin_HEXAGON_V6_vlsrhv",
+    "llvm.hexagon.V6.vlsrhv.128B" => "__builtin_HEXAGON_V6_vlsrhv_128B",
+    "llvm.hexagon.V6.vlsrw" => "__builtin_HEXAGON_V6_vlsrw",
+    "llvm.hexagon.V6.vlsrw.128B" => "__builtin_HEXAGON_V6_vlsrw_128B",
+    "llvm.hexagon.V6.vlsrwv" => "__builtin_HEXAGON_V6_vlsrwv",
+    "llvm.hexagon.V6.vlsrwv.128B" => "__builtin_HEXAGON_V6_vlsrwv_128B",
+    "llvm.hexagon.V6.vlutb" => "__builtin_HEXAGON_V6_vlutb",
+    "llvm.hexagon.V6.vlutb.128B" => "__builtin_HEXAGON_V6_vlutb_128B",
+    "llvm.hexagon.V6.vlutb.acc" => "__builtin_HEXAGON_V6_vlutb_acc",
+    "llvm.hexagon.V6.vlutb.acc.128B" => "__builtin_HEXAGON_V6_vlutb_acc_128B",
+    "llvm.hexagon.V6.vlutb.dv" => "__builtin_HEXAGON_V6_vlutb_dv",
+    "llvm.hexagon.V6.vlutb.dv.128B" => "__builtin_HEXAGON_V6_vlutb_dv_128B",
+    "llvm.hexagon.V6.vlutb.dv.acc" => "__builtin_HEXAGON_V6_vlutb_dv_acc",
+    "llvm.hexagon.V6.vlutb.dv.acc.128B" => "__builtin_HEXAGON_V6_vlutb_dv_acc_128B",
+    "llvm.hexagon.V6.vlutvvb" => "__builtin_HEXAGON_V6_vlutvvb",
+    "llvm.hexagon.V6.vlutvvb.128B" => "__builtin_HEXAGON_V6_vlutvvb_128B",
+    "llvm.hexagon.V6.vlutvvb.oracc" => "__builtin_HEXAGON_V6_vlutvvb_oracc",
+    "llvm.hexagon.V6.vlutvvb.oracc.128B" => "__builtin_HEXAGON_V6_vlutvvb_oracc_128B",
+    "llvm.hexagon.V6.vlutvwh" => "__builtin_HEXAGON_V6_vlutvwh",
+    "llvm.hexagon.V6.vlutvwh.128B" => "__builtin_HEXAGON_V6_vlutvwh_128B",
+    "llvm.hexagon.V6.vlutvwh.oracc" => "__builtin_HEXAGON_V6_vlutvwh_oracc",
+    "llvm.hexagon.V6.vlutvwh.oracc.128B" => "__builtin_HEXAGON_V6_vlutvwh_oracc_128B",
+    "llvm.hexagon.V6.vmaxh" => "__builtin_HEXAGON_V6_vmaxh",
+    "llvm.hexagon.V6.vmaxh.128B" => "__builtin_HEXAGON_V6_vmaxh_128B",
+    "llvm.hexagon.V6.vmaxub" => "__builtin_HEXAGON_V6_vmaxub",
+    "llvm.hexagon.V6.vmaxub.128B" => "__builtin_HEXAGON_V6_vmaxub_128B",
+    "llvm.hexagon.V6.vmaxuh" => "__builtin_HEXAGON_V6_vmaxuh",
+    "llvm.hexagon.V6.vmaxuh.128B" => "__builtin_HEXAGON_V6_vmaxuh_128B",
+    "llvm.hexagon.V6.vmaxw" => "__builtin_HEXAGON_V6_vmaxw",
+    "llvm.hexagon.V6.vmaxw.128B" => "__builtin_HEXAGON_V6_vmaxw_128B",
+    "llvm.hexagon.V6.vminh" => "__builtin_HEXAGON_V6_vminh",
+    "llvm.hexagon.V6.vminh.128B" => "__builtin_HEXAGON_V6_vminh_128B",
+    "llvm.hexagon.V6.vminub" => "__builtin_HEXAGON_V6_vminub",
+    "llvm.hexagon.V6.vminub.128B" => "__builtin_HEXAGON_V6_vminub_128B",
+    "llvm.hexagon.V6.vminuh" => "__builtin_HEXAGON_V6_vminuh",
+    "llvm.hexagon.V6.vminuh.128B" => "__builtin_HEXAGON_V6_vminuh_128B",
+    "llvm.hexagon.V6.vminw" => "__builtin_HEXAGON_V6_vminw",
+    "llvm.hexagon.V6.vminw.128B" => "__builtin_HEXAGON_V6_vminw_128B",
+    "llvm.hexagon.V6.vmpabus" => "__builtin_HEXAGON_V6_vmpabus",
+    "llvm.hexagon.V6.vmpabus.128B" => "__builtin_HEXAGON_V6_vmpabus_128B",
+    "llvm.hexagon.V6.vmpabus.acc" => "__builtin_HEXAGON_V6_vmpabus_acc",
+    "llvm.hexagon.V6.vmpabus.acc.128B" => "__builtin_HEXAGON_V6_vmpabus_acc_128B",
+    "llvm.hexagon.V6.vmpabusv" => "__builtin_HEXAGON_V6_vmpabusv",
+    "llvm.hexagon.V6.vmpabusv.128B" => "__builtin_HEXAGON_V6_vmpabusv_128B",
+    "llvm.hexagon.V6.vmpabuuv" => "__builtin_HEXAGON_V6_vmpabuuv",
+    "llvm.hexagon.V6.vmpabuuv.128B" => "__builtin_HEXAGON_V6_vmpabuuv_128B",
+    "llvm.hexagon.V6.vmpahb" => "__builtin_HEXAGON_V6_vmpahb",
+    "llvm.hexagon.V6.vmpahb.128B" => "__builtin_HEXAGON_V6_vmpahb_128B",
+    "llvm.hexagon.V6.vmpahb.acc" => "__builtin_HEXAGON_V6_vmpahb_acc",
+    "llvm.hexagon.V6.vmpahb.acc.128B" => "__builtin_HEXAGON_V6_vmpahb_acc_128B",
+    "llvm.hexagon.V6.vmpybus" => "__builtin_HEXAGON_V6_vmpybus",
+    "llvm.hexagon.V6.vmpybus.128B" => "__builtin_HEXAGON_V6_vmpybus_128B",
+    "llvm.hexagon.V6.vmpybus.acc" => "__builtin_HEXAGON_V6_vmpybus_acc",
+    "llvm.hexagon.V6.vmpybus.acc.128B" => "__builtin_HEXAGON_V6_vmpybus_acc_128B",
+    "llvm.hexagon.V6.vmpybusv" => "__builtin_HEXAGON_V6_vmpybusv",
+    "llvm.hexagon.V6.vmpybusv.128B" => "__builtin_HEXAGON_V6_vmpybusv_128B",
+    "llvm.hexagon.V6.vmpybusv.acc" => "__builtin_HEXAGON_V6_vmpybusv_acc",
+    "llvm.hexagon.V6.vmpybusv.acc.128B" => "__builtin_HEXAGON_V6_vmpybusv_acc_128B",
+    "llvm.hexagon.V6.vmpybv" => "__builtin_HEXAGON_V6_vmpybv",
+    "llvm.hexagon.V6.vmpybv.128B" => "__builtin_HEXAGON_V6_vmpybv_128B",
+    "llvm.hexagon.V6.vmpybv.acc" => "__builtin_HEXAGON_V6_vmpybv_acc",
+    "llvm.hexagon.V6.vmpybv.acc.128B" => "__builtin_HEXAGON_V6_vmpybv_acc_128B",
+    "llvm.hexagon.V6.vmpyewuh" => "__builtin_HEXAGON_V6_vmpyewuh",
+    "llvm.hexagon.V6.vmpyewuh.128B" => "__builtin_HEXAGON_V6_vmpyewuh_128B",
+    "llvm.hexagon.V6.vmpyh" => "__builtin_HEXAGON_V6_vmpyh",
+    "llvm.hexagon.V6.vmpyh.128B" => "__builtin_HEXAGON_V6_vmpyh_128B",
+    "llvm.hexagon.V6.vmpyhsat.acc" => "__builtin_HEXAGON_V6_vmpyhsat_acc",
+    "llvm.hexagon.V6.vmpyhsat.acc.128B" => "__builtin_HEXAGON_V6_vmpyhsat_acc_128B",
+    "llvm.hexagon.V6.vmpyhsrs" => "__builtin_HEXAGON_V6_vmpyhsrs",
+    "llvm.hexagon.V6.vmpyhsrs.128B" => "__builtin_HEXAGON_V6_vmpyhsrs_128B",
+    "llvm.hexagon.V6.vmpyhss" => "__builtin_HEXAGON_V6_vmpyhss",
+    "llvm.hexagon.V6.vmpyhss.128B" => "__builtin_HEXAGON_V6_vmpyhss_128B",
+    "llvm.hexagon.V6.vmpyhus" => "__builtin_HEXAGON_V6_vmpyhus",
+    "llvm.hexagon.V6.vmpyhus.128B" => "__builtin_HEXAGON_V6_vmpyhus_128B",
+    "llvm.hexagon.V6.vmpyhus.acc" => "__builtin_HEXAGON_V6_vmpyhus_acc",
+    "llvm.hexagon.V6.vmpyhus.acc.128B" => "__builtin_HEXAGON_V6_vmpyhus_acc_128B",
+    "llvm.hexagon.V6.vmpyhv" => "__builtin_HEXAGON_V6_vmpyhv",
+    "llvm.hexagon.V6.vmpyhv.128B" => "__builtin_HEXAGON_V6_vmpyhv_128B",
+    "llvm.hexagon.V6.vmpyhv.acc" => "__builtin_HEXAGON_V6_vmpyhv_acc",
+    "llvm.hexagon.V6.vmpyhv.acc.128B" => "__builtin_HEXAGON_V6_vmpyhv_acc_128B",
+    "llvm.hexagon.V6.vmpyhvsrs" => "__builtin_HEXAGON_V6_vmpyhvsrs",
+    "llvm.hexagon.V6.vmpyhvsrs.128B" => "__builtin_HEXAGON_V6_vmpyhvsrs_128B",
+    "llvm.hexagon.V6.vmpyieoh" => "__builtin_HEXAGON_V6_vmpyieoh",
+    "llvm.hexagon.V6.vmpyieoh.128B" => "__builtin_HEXAGON_V6_vmpyieoh_128B",
+    "llvm.hexagon.V6.vmpyiewh.acc" => "__builtin_HEXAGON_V6_vmpyiewh_acc",
+    "llvm.hexagon.V6.vmpyiewh.acc.128B" => "__builtin_HEXAGON_V6_vmpyiewh_acc_128B",
+    "llvm.hexagon.V6.vmpyiewuh" => "__builtin_HEXAGON_V6_vmpyiewuh",
+    "llvm.hexagon.V6.vmpyiewuh.128B" => "__builtin_HEXAGON_V6_vmpyiewuh_128B",
+    "llvm.hexagon.V6.vmpyiewuh.acc" => "__builtin_HEXAGON_V6_vmpyiewuh_acc",
+    "llvm.hexagon.V6.vmpyiewuh.acc.128B" => "__builtin_HEXAGON_V6_vmpyiewuh_acc_128B",
+    "llvm.hexagon.V6.vmpyih" => "__builtin_HEXAGON_V6_vmpyih",
+    "llvm.hexagon.V6.vmpyih.128B" => "__builtin_HEXAGON_V6_vmpyih_128B",
+    "llvm.hexagon.V6.vmpyih.acc" => "__builtin_HEXAGON_V6_vmpyih_acc",
+    "llvm.hexagon.V6.vmpyih.acc.128B" => "__builtin_HEXAGON_V6_vmpyih_acc_128B",
+    "llvm.hexagon.V6.vmpyihb" => "__builtin_HEXAGON_V6_vmpyihb",
+    "llvm.hexagon.V6.vmpyihb.128B" => "__builtin_HEXAGON_V6_vmpyihb_128B",
+    "llvm.hexagon.V6.vmpyihb.acc" => "__builtin_HEXAGON_V6_vmpyihb_acc",
+    "llvm.hexagon.V6.vmpyihb.acc.128B" => "__builtin_HEXAGON_V6_vmpyihb_acc_128B",
+    "llvm.hexagon.V6.vmpyiowh" => "__builtin_HEXAGON_V6_vmpyiowh",
+    "llvm.hexagon.V6.vmpyiowh.128B" => "__builtin_HEXAGON_V6_vmpyiowh_128B",
+    "llvm.hexagon.V6.vmpyiwb" => "__builtin_HEXAGON_V6_vmpyiwb",
+    "llvm.hexagon.V6.vmpyiwb.128B" => "__builtin_HEXAGON_V6_vmpyiwb_128B",
+    "llvm.hexagon.V6.vmpyiwb.acc" => "__builtin_HEXAGON_V6_vmpyiwb_acc",
+    "llvm.hexagon.V6.vmpyiwb.acc.128B" => "__builtin_HEXAGON_V6_vmpyiwb_acc_128B",
+    "llvm.hexagon.V6.vmpyiwh" => "__builtin_HEXAGON_V6_vmpyiwh",
+    "llvm.hexagon.V6.vmpyiwh.128B" => "__builtin_HEXAGON_V6_vmpyiwh_128B",
+    "llvm.hexagon.V6.vmpyiwh.acc" => "__builtin_HEXAGON_V6_vmpyiwh_acc",
+    "llvm.hexagon.V6.vmpyiwh.acc.128B" => "__builtin_HEXAGON_V6_vmpyiwh_acc_128B",
+    "llvm.hexagon.V6.vmpyowh" => "__builtin_HEXAGON_V6_vmpyowh",
+    "llvm.hexagon.V6.vmpyowh.128B" => "__builtin_HEXAGON_V6_vmpyowh_128B",
+    "llvm.hexagon.V6.vmpyowh.rnd" => "__builtin_HEXAGON_V6_vmpyowh_rnd",
+    "llvm.hexagon.V6.vmpyowh.rnd.128B" => "__builtin_HEXAGON_V6_vmpyowh_rnd_128B",
+    "llvm.hexagon.V6.vmpyowh.rnd.sacc" => "__builtin_HEXAGON_V6_vmpyowh_rnd_sacc",
+    "llvm.hexagon.V6.vmpyowh.rnd.sacc.128B" => "__builtin_HEXAGON_V6_vmpyowh_rnd_sacc_128B",
+    "llvm.hexagon.V6.vmpyowh.sacc" => "__builtin_HEXAGON_V6_vmpyowh_sacc",
+    "llvm.hexagon.V6.vmpyowh.sacc.128B" => "__builtin_HEXAGON_V6_vmpyowh_sacc_128B",
+    "llvm.hexagon.V6.vmpyub" => "__builtin_HEXAGON_V6_vmpyub",
+    "llvm.hexagon.V6.vmpyub.128B" => "__builtin_HEXAGON_V6_vmpyub_128B",
+    "llvm.hexagon.V6.vmpyub.acc" => "__builtin_HEXAGON_V6_vmpyub_acc",
+    "llvm.hexagon.V6.vmpyub.acc.128B" => "__builtin_HEXAGON_V6_vmpyub_acc_128B",
+    "llvm.hexagon.V6.vmpyubv" => "__builtin_HEXAGON_V6_vmpyubv",
+    "llvm.hexagon.V6.vmpyubv.128B" => "__builtin_HEXAGON_V6_vmpyubv_128B",
+    "llvm.hexagon.V6.vmpyubv.acc" => "__builtin_HEXAGON_V6_vmpyubv_acc",
+    "llvm.hexagon.V6.vmpyubv.acc.128B" => "__builtin_HEXAGON_V6_vmpyubv_acc_128B",
+    "llvm.hexagon.V6.vmpyuh" => "__builtin_HEXAGON_V6_vmpyuh",
+    "llvm.hexagon.V6.vmpyuh.128B" => "__builtin_HEXAGON_V6_vmpyuh_128B",
+    "llvm.hexagon.V6.vmpyuh.acc" => "__builtin_HEXAGON_V6_vmpyuh_acc",
+    "llvm.hexagon.V6.vmpyuh.acc.128B" => "__builtin_HEXAGON_V6_vmpyuh_acc_128B",
+    "llvm.hexagon.V6.vmpyuhv" => "__builtin_HEXAGON_V6_vmpyuhv",
+    "llvm.hexagon.V6.vmpyuhv.128B" => "__builtin_HEXAGON_V6_vmpyuhv_128B",
+    "llvm.hexagon.V6.vmpyuhv.acc" => "__builtin_HEXAGON_V6_vmpyuhv_acc",
+    "llvm.hexagon.V6.vmpyuhv.acc.128B" => "__builtin_HEXAGON_V6_vmpyuhv_acc_128B",
+    "llvm.hexagon.V6.vnavgh" => "__builtin_HEXAGON_V6_vnavgh",
+    "llvm.hexagon.V6.vnavgh.128B" => "__builtin_HEXAGON_V6_vnavgh_128B",
+    "llvm.hexagon.V6.vnavgub" => "__builtin_HEXAGON_V6_vnavgub",
+    "llvm.hexagon.V6.vnavgub.128B" => "__builtin_HEXAGON_V6_vnavgub_128B",
+    "llvm.hexagon.V6.vnavgw" => "__builtin_HEXAGON_V6_vnavgw",
+    "llvm.hexagon.V6.vnavgw.128B" => "__builtin_HEXAGON_V6_vnavgw_128B",
+    "llvm.hexagon.V6.vnormamth" => "__builtin_HEXAGON_V6_vnormamth",
+    "llvm.hexagon.V6.vnormamth.128B" => "__builtin_HEXAGON_V6_vnormamth_128B",
+    "llvm.hexagon.V6.vnormamtw" => "__builtin_HEXAGON_V6_vnormamtw",
+    "llvm.hexagon.V6.vnormamtw.128B" => "__builtin_HEXAGON_V6_vnormamtw_128B",
+    "llvm.hexagon.V6.vnot" => "__builtin_HEXAGON_V6_vnot",
+    "llvm.hexagon.V6.vnot.128B" => "__builtin_HEXAGON_V6_vnot_128B",
+    "llvm.hexagon.V6.vor" => "__builtin_HEXAGON_V6_vor",
+    "llvm.hexagon.V6.vor.128B" => "__builtin_HEXAGON_V6_vor_128B",
+    "llvm.hexagon.V6.vpackeb" => "__builtin_HEXAGON_V6_vpackeb",
+    "llvm.hexagon.V6.vpackeb.128B" => "__builtin_HEXAGON_V6_vpackeb_128B",
+    "llvm.hexagon.V6.vpackeh" => "__builtin_HEXAGON_V6_vpackeh",
+    "llvm.hexagon.V6.vpackeh.128B" => "__builtin_HEXAGON_V6_vpackeh_128B",
+    "llvm.hexagon.V6.vpackhb.sat" => "__builtin_HEXAGON_V6_vpackhb_sat",
+    "llvm.hexagon.V6.vpackhb.sat.128B" => "__builtin_HEXAGON_V6_vpackhb_sat_128B",
+    "llvm.hexagon.V6.vpackhub.sat" => "__builtin_HEXAGON_V6_vpackhub_sat",
+    "llvm.hexagon.V6.vpackhub.sat.128B" => "__builtin_HEXAGON_V6_vpackhub_sat_128B",
+    "llvm.hexagon.V6.vpackob" => "__builtin_HEXAGON_V6_vpackob",
+    "llvm.hexagon.V6.vpackob.128B" => "__builtin_HEXAGON_V6_vpackob_128B",
+    "llvm.hexagon.V6.vpackoh" => "__builtin_HEXAGON_V6_vpackoh",
+    "llvm.hexagon.V6.vpackoh.128B" => "__builtin_HEXAGON_V6_vpackoh_128B",
+    "llvm.hexagon.V6.vpackwh.sat" => "__builtin_HEXAGON_V6_vpackwh_sat",
+    "llvm.hexagon.V6.vpackwh.sat.128B" => "__builtin_HEXAGON_V6_vpackwh_sat_128B",
+    "llvm.hexagon.V6.vpackwuh.sat" => "__builtin_HEXAGON_V6_vpackwuh_sat",
+    "llvm.hexagon.V6.vpackwuh.sat.128B" => "__builtin_HEXAGON_V6_vpackwuh_sat_128B",
+    "llvm.hexagon.V6.vpopcounth" => "__builtin_HEXAGON_V6_vpopcounth",
+    "llvm.hexagon.V6.vpopcounth.128B" => "__builtin_HEXAGON_V6_vpopcounth_128B",
+    "llvm.hexagon.V6.vrdelta" => "__builtin_HEXAGON_V6_vrdelta",
+    "llvm.hexagon.V6.vrdelta.128B" => "__builtin_HEXAGON_V6_vrdelta_128B",
+    "llvm.hexagon.V6.vrmpybus" => "__builtin_HEXAGON_V6_vrmpybus",
+    "llvm.hexagon.V6.vrmpybus.128B" => "__builtin_HEXAGON_V6_vrmpybus_128B",
+    "llvm.hexagon.V6.vrmpybus.acc" => "__builtin_HEXAGON_V6_vrmpybus_acc",
+    "llvm.hexagon.V6.vrmpybus.acc.128B" => "__builtin_HEXAGON_V6_vrmpybus_acc_128B",
+    "llvm.hexagon.V6.vrmpybusi" => "__builtin_HEXAGON_V6_vrmpybusi",
+    "llvm.hexagon.V6.vrmpybusi.128B" => "__builtin_HEXAGON_V6_vrmpybusi_128B",
+    "llvm.hexagon.V6.vrmpybusi.acc" => "__builtin_HEXAGON_V6_vrmpybusi_acc",
+    "llvm.hexagon.V6.vrmpybusi.acc.128B" => "__builtin_HEXAGON_V6_vrmpybusi_acc_128B",
+    "llvm.hexagon.V6.vrmpybusv" => "__builtin_HEXAGON_V6_vrmpybusv",
+    "llvm.hexagon.V6.vrmpybusv.128B" => "__builtin_HEXAGON_V6_vrmpybusv_128B",
+    "llvm.hexagon.V6.vrmpybusv.acc" => "__builtin_HEXAGON_V6_vrmpybusv_acc",
+    "llvm.hexagon.V6.vrmpybusv.acc.128B" => "__builtin_HEXAGON_V6_vrmpybusv_acc_128B",
+    "llvm.hexagon.V6.vrmpybv" => "__builtin_HEXAGON_V6_vrmpybv",
+    "llvm.hexagon.V6.vrmpybv.128B" => "__builtin_HEXAGON_V6_vrmpybv_128B",
+    "llvm.hexagon.V6.vrmpybv.acc" => "__builtin_HEXAGON_V6_vrmpybv_acc",
+    "llvm.hexagon.V6.vrmpybv.acc.128B" => "__builtin_HEXAGON_V6_vrmpybv_acc_128B",
+    "llvm.hexagon.V6.vrmpyub" => "__builtin_HEXAGON_V6_vrmpyub",
+    "llvm.hexagon.V6.vrmpyub.128B" => "__builtin_HEXAGON_V6_vrmpyub_128B",
+    "llvm.hexagon.V6.vrmpyub.acc" => "__builtin_HEXAGON_V6_vrmpyub_acc",
+    "llvm.hexagon.V6.vrmpyub.acc.128B" => "__builtin_HEXAGON_V6_vrmpyub_acc_128B",
+    "llvm.hexagon.V6.vrmpyubi" => "__builtin_HEXAGON_V6_vrmpyubi",
+    "llvm.hexagon.V6.vrmpyubi.128B" => "__builtin_HEXAGON_V6_vrmpyubi_128B",
+    "llvm.hexagon.V6.vrmpyubi.acc" => "__builtin_HEXAGON_V6_vrmpyubi_acc",
+    "llvm.hexagon.V6.vrmpyubi.acc.128B" => "__builtin_HEXAGON_V6_vrmpyubi_acc_128B",
+    "llvm.hexagon.V6.vrmpyubv" => "__builtin_HEXAGON_V6_vrmpyubv",
+    "llvm.hexagon.V6.vrmpyubv.128B" => "__builtin_HEXAGON_V6_vrmpyubv_128B",
+    "llvm.hexagon.V6.vrmpyubv.acc" => "__builtin_HEXAGON_V6_vrmpyubv_acc",
+    "llvm.hexagon.V6.vrmpyubv.acc.128B" => "__builtin_HEXAGON_V6_vrmpyubv_acc_128B",
+    "llvm.hexagon.V6.vror" => "__builtin_HEXAGON_V6_vror",
+    "llvm.hexagon.V6.vror.128B" => "__builtin_HEXAGON_V6_vror_128B",
+    "llvm.hexagon.V6.vroundhb" => "__builtin_HEXAGON_V6_vroundhb",
+    "llvm.hexagon.V6.vroundhb.128B" => "__builtin_HEXAGON_V6_vroundhb_128B",
+    "llvm.hexagon.V6.vroundhub" => "__builtin_HEXAGON_V6_vroundhub",
+    "llvm.hexagon.V6.vroundhub.128B" => "__builtin_HEXAGON_V6_vroundhub_128B",
+    "llvm.hexagon.V6.vroundwh" => "__builtin_HEXAGON_V6_vroundwh",
+    "llvm.hexagon.V6.vroundwh.128B" => "__builtin_HEXAGON_V6_vroundwh_128B",
+    "llvm.hexagon.V6.vroundwuh" => "__builtin_HEXAGON_V6_vroundwuh",
+    "llvm.hexagon.V6.vroundwuh.128B" => "__builtin_HEXAGON_V6_vroundwuh_128B",
+    "llvm.hexagon.V6.vrsadubi" => "__builtin_HEXAGON_V6_vrsadubi",
+    "llvm.hexagon.V6.vrsadubi.128B" => "__builtin_HEXAGON_V6_vrsadubi_128B",
+    "llvm.hexagon.V6.vrsadubi.acc" => "__builtin_HEXAGON_V6_vrsadubi_acc",
+    "llvm.hexagon.V6.vrsadubi.acc.128B" => "__builtin_HEXAGON_V6_vrsadubi_acc_128B",
+    "llvm.hexagon.V6.vsathub" => "__builtin_HEXAGON_V6_vsathub",
+    "llvm.hexagon.V6.vsathub.128B" => "__builtin_HEXAGON_V6_vsathub_128B",
+    "llvm.hexagon.V6.vsatwh" => "__builtin_HEXAGON_V6_vsatwh",
+    "llvm.hexagon.V6.vsatwh.128B" => "__builtin_HEXAGON_V6_vsatwh_128B",
+    "llvm.hexagon.V6.vsb" => "__builtin_HEXAGON_V6_vsb",
+    "llvm.hexagon.V6.vsb.128B" => "__builtin_HEXAGON_V6_vsb_128B",
+    "llvm.hexagon.V6.vsh" => "__builtin_HEXAGON_V6_vsh",
+    "llvm.hexagon.V6.vsh.128B" => "__builtin_HEXAGON_V6_vsh_128B",
+    "llvm.hexagon.V6.vshufeh" => "__builtin_HEXAGON_V6_vshufeh",
+    "llvm.hexagon.V6.vshufeh.128B" => "__builtin_HEXAGON_V6_vshufeh_128B",
+    "llvm.hexagon.V6.vshuffb" => "__builtin_HEXAGON_V6_vshuffb",
+    "llvm.hexagon.V6.vshuffb.128B" => "__builtin_HEXAGON_V6_vshuffb_128B",
+    "llvm.hexagon.V6.vshuffeb" => "__builtin_HEXAGON_V6_vshuffeb",
+    "llvm.hexagon.V6.vshuffeb.128B" => "__builtin_HEXAGON_V6_vshuffeb_128B",
+    "llvm.hexagon.V6.vshuffh" => "__builtin_HEXAGON_V6_vshuffh",
+    "llvm.hexagon.V6.vshuffh.128B" => "__builtin_HEXAGON_V6_vshuffh_128B",
+    "llvm.hexagon.V6.vshuffob" => "__builtin_HEXAGON_V6_vshuffob",
+    "llvm.hexagon.V6.vshuffob.128B" => "__builtin_HEXAGON_V6_vshuffob_128B",
+    "llvm.hexagon.V6.vshuffvdd" => "__builtin_HEXAGON_V6_vshuffvdd",
+    "llvm.hexagon.V6.vshuffvdd.128B" => "__builtin_HEXAGON_V6_vshuffvdd_128B",
+    "llvm.hexagon.V6.vshufoeb" => "__builtin_HEXAGON_V6_vshufoeb",
+    "llvm.hexagon.V6.vshufoeb.128B" => "__builtin_HEXAGON_V6_vshufoeb_128B",
+    "llvm.hexagon.V6.vshufoeh" => "__builtin_HEXAGON_V6_vshufoeh",
+    "llvm.hexagon.V6.vshufoeh.128B" => "__builtin_HEXAGON_V6_vshufoeh_128B",
+    "llvm.hexagon.V6.vshufoh" => "__builtin_HEXAGON_V6_vshufoh",
+    "llvm.hexagon.V6.vshufoh.128B" => "__builtin_HEXAGON_V6_vshufoh_128B",
+    "llvm.hexagon.V6.vsubb" => "__builtin_HEXAGON_V6_vsubb",
+    "llvm.hexagon.V6.vsubb.128B" => "__builtin_HEXAGON_V6_vsubb_128B",
+    "llvm.hexagon.V6.vsubb.dv" => "__builtin_HEXAGON_V6_vsubb_dv",
+    "llvm.hexagon.V6.vsubb.dv.128B" => "__builtin_HEXAGON_V6_vsubb_dv_128B",
+    "llvm.hexagon.V6.vsubh" => "__builtin_HEXAGON_V6_vsubh",
+    "llvm.hexagon.V6.vsubh.128B" => "__builtin_HEXAGON_V6_vsubh_128B",
+    "llvm.hexagon.V6.vsubh.dv" => "__builtin_HEXAGON_V6_vsubh_dv",
+    "llvm.hexagon.V6.vsubh.dv.128B" => "__builtin_HEXAGON_V6_vsubh_dv_128B",
+    "llvm.hexagon.V6.vsubhsat" => "__builtin_HEXAGON_V6_vsubhsat",
+    "llvm.hexagon.V6.vsubhsat.128B" => "__builtin_HEXAGON_V6_vsubhsat_128B",
+    "llvm.hexagon.V6.vsubhsat.dv" => "__builtin_HEXAGON_V6_vsubhsat_dv",
+    "llvm.hexagon.V6.vsubhsat.dv.128B" => "__builtin_HEXAGON_V6_vsubhsat_dv_128B",
+    "llvm.hexagon.V6.vsubhw" => "__builtin_HEXAGON_V6_vsubhw",
+    "llvm.hexagon.V6.vsubhw.128B" => "__builtin_HEXAGON_V6_vsubhw_128B",
+    "llvm.hexagon.V6.vsububh" => "__builtin_HEXAGON_V6_vsububh",
+    "llvm.hexagon.V6.vsububh.128B" => "__builtin_HEXAGON_V6_vsububh_128B",
+    "llvm.hexagon.V6.vsububsat" => "__builtin_HEXAGON_V6_vsububsat",
+    "llvm.hexagon.V6.vsububsat.128B" => "__builtin_HEXAGON_V6_vsububsat_128B",
+    "llvm.hexagon.V6.vsububsat.dv" => "__builtin_HEXAGON_V6_vsububsat_dv",
+    "llvm.hexagon.V6.vsububsat.dv.128B" => "__builtin_HEXAGON_V6_vsububsat_dv_128B",
+    "llvm.hexagon.V6.vsubuhsat" => "__builtin_HEXAGON_V6_vsubuhsat",
+    "llvm.hexagon.V6.vsubuhsat.128B" => "__builtin_HEXAGON_V6_vsubuhsat_128B",
+    "llvm.hexagon.V6.vsubuhsat.dv" => "__builtin_HEXAGON_V6_vsubuhsat_dv",
+    "llvm.hexagon.V6.vsubuhsat.dv.128B" => "__builtin_HEXAGON_V6_vsubuhsat_dv_128B",
+    "llvm.hexagon.V6.vsubuhw" => "__builtin_HEXAGON_V6_vsubuhw",
+    "llvm.hexagon.V6.vsubuhw.128B" => "__builtin_HEXAGON_V6_vsubuhw_128B",
+    "llvm.hexagon.V6.vsubw" => "__builtin_HEXAGON_V6_vsubw",
+    "llvm.hexagon.V6.vsubw.128B" => "__builtin_HEXAGON_V6_vsubw_128B",
+    "llvm.hexagon.V6.vsubw.dv" => "__builtin_HEXAGON_V6_vsubw_dv",
+    "llvm.hexagon.V6.vsubw.dv.128B" => "__builtin_HEXAGON_V6_vsubw_dv_128B",
+    "llvm.hexagon.V6.vsubwsat" => "__builtin_HEXAGON_V6_vsubwsat",
+    "llvm.hexagon.V6.vsubwsat.128B" => "__builtin_HEXAGON_V6_vsubwsat_128B",
+    "llvm.hexagon.V6.vsubwsat.dv" => "__builtin_HEXAGON_V6_vsubwsat_dv",
+    "llvm.hexagon.V6.vsubwsat.dv.128B" => "__builtin_HEXAGON_V6_vsubwsat_dv_128B",
+    "llvm.hexagon.V6.vtmpyb" => "__builtin_HEXAGON_V6_vtmpyb",
+    "llvm.hexagon.V6.vtmpyb.128B" => "__builtin_HEXAGON_V6_vtmpyb_128B",
+    "llvm.hexagon.V6.vtmpyb.acc" => "__builtin_HEXAGON_V6_vtmpyb_acc",
+    "llvm.hexagon.V6.vtmpyb.acc.128B" => "__builtin_HEXAGON_V6_vtmpyb_acc_128B",
+    "llvm.hexagon.V6.vtmpybus" => "__builtin_HEXAGON_V6_vtmpybus",
+    "llvm.hexagon.V6.vtmpybus.128B" => "__builtin_HEXAGON_V6_vtmpybus_128B",
+    "llvm.hexagon.V6.vtmpybus.acc" => "__builtin_HEXAGON_V6_vtmpybus_acc",
+    "llvm.hexagon.V6.vtmpybus.acc.128B" => "__builtin_HEXAGON_V6_vtmpybus_acc_128B",
+    "llvm.hexagon.V6.vtmpyhb" => "__builtin_HEXAGON_V6_vtmpyhb",
+    "llvm.hexagon.V6.vtmpyhb.128B" => "__builtin_HEXAGON_V6_vtmpyhb_128B",
+    "llvm.hexagon.V6.vtmpyhb.acc" => "__builtin_HEXAGON_V6_vtmpyhb_acc",
+    "llvm.hexagon.V6.vtmpyhb.acc.128B" => "__builtin_HEXAGON_V6_vtmpyhb_acc_128B",
+    "llvm.hexagon.V6.vunpackb" => "__builtin_HEXAGON_V6_vunpackb",
+    "llvm.hexagon.V6.vunpackb.128B" => "__builtin_HEXAGON_V6_vunpackb_128B",
+    "llvm.hexagon.V6.vunpackh" => "__builtin_HEXAGON_V6_vunpackh",
+    "llvm.hexagon.V6.vunpackh.128B" => "__builtin_HEXAGON_V6_vunpackh_128B",
+    "llvm.hexagon.V6.vunpackob" => "__builtin_HEXAGON_V6_vunpackob",
+    "llvm.hexagon.V6.vunpackob.128B" => "__builtin_HEXAGON_V6_vunpackob_128B",
+    "llvm.hexagon.V6.vunpackoh" => "__builtin_HEXAGON_V6_vunpackoh",
+    "llvm.hexagon.V6.vunpackoh.128B" => "__builtin_HEXAGON_V6_vunpackoh_128B",
+    "llvm.hexagon.V6.vunpackub" => "__builtin_HEXAGON_V6_vunpackub",
+    "llvm.hexagon.V6.vunpackub.128B" => "__builtin_HEXAGON_V6_vunpackub_128B",
+    "llvm.hexagon.V6.vunpackuh" => "__builtin_HEXAGON_V6_vunpackuh",
+    "llvm.hexagon.V6.vunpackuh.128B" => "__builtin_HEXAGON_V6_vunpackuh_128B",
+    "llvm.hexagon.V6.vxor" => "__builtin_HEXAGON_V6_vxor",
+    "llvm.hexagon.V6.vxor.128B" => "__builtin_HEXAGON_V6_vxor_128B",
+    "llvm.hexagon.V6.vzb" => "__builtin_HEXAGON_V6_vzb",
+    "llvm.hexagon.V6.vzb.128B" => "__builtin_HEXAGON_V6_vzb_128B",
+    "llvm.hexagon.V6.vzh" => "__builtin_HEXAGON_V6_vzh",
+    "llvm.hexagon.V6.vzh.128B" => "__builtin_HEXAGON_V6_vzh_128B",
+    "llvm.hexagon.brev.ldb" => "__builtin_brev_ldb",
+    "llvm.hexagon.brev.ldd" => "__builtin_brev_ldd",
+    "llvm.hexagon.brev.ldh" => "__builtin_brev_ldh",
+    "llvm.hexagon.brev.ldub" => "__builtin_brev_ldub",
+    "llvm.hexagon.brev.lduh" => "__builtin_brev_lduh",
+    "llvm.hexagon.brev.ldw" => "__builtin_brev_ldw",
+    "llvm.hexagon.brev.stb" => "__builtin_brev_stb",
+    "llvm.hexagon.brev.std" => "__builtin_brev_std",
+    "llvm.hexagon.brev.sth" => "__builtin_brev_sth",
+    "llvm.hexagon.brev.sthhi" => "__builtin_brev_sthhi",
+    "llvm.hexagon.brev.stw" => "__builtin_brev_stw",
+    "llvm.hexagon.circ.ldb" => "__builtin_circ_ldb",
+    "llvm.hexagon.circ.ldd" => "__builtin_circ_ldd",
+    "llvm.hexagon.circ.ldh" => "__builtin_circ_ldh",
+    "llvm.hexagon.circ.ldub" => "__builtin_circ_ldub",
+    "llvm.hexagon.circ.lduh" => "__builtin_circ_lduh",
+    "llvm.hexagon.circ.ldw" => "__builtin_circ_ldw",
+    "llvm.hexagon.circ.stb" => "__builtin_circ_stb",
+    "llvm.hexagon.circ.std" => "__builtin_circ_std",
+    "llvm.hexagon.circ.sth" => "__builtin_circ_sth",
+    "llvm.hexagon.circ.sthhi" => "__builtin_circ_sthhi",
+    "llvm.hexagon.circ.stw" => "__builtin_circ_stw",
+    "llvm.hexagon.mm256i.vaddw" => "__builtin__mm256i_vaddw",
+    "llvm.hexagon.prefetch" => "__builtin_HEXAGON_prefetch",
+    // mips
+    "llvm.mips.absq.s.ph" => "__builtin_mips_absq_s_ph",
+    "llvm.mips.absq.s.qb" => "__builtin_mips_absq_s_qb",
+    "llvm.mips.absq.s.w" => "__builtin_mips_absq_s_w",
+    "llvm.mips.add.a.b" => "__builtin_msa_add_a_b",
+    "llvm.mips.add.a.d" => "__builtin_msa_add_a_d",
+    "llvm.mips.add.a.h" => "__builtin_msa_add_a_h",
+    "llvm.mips.add.a.w" => "__builtin_msa_add_a_w",
+    "llvm.mips.addq.ph" => "__builtin_mips_addq_ph",
+    "llvm.mips.addq.s.ph" => "__builtin_mips_addq_s_ph",
+    "llvm.mips.addq.s.w" => "__builtin_mips_addq_s_w",
+    "llvm.mips.addqh.ph" => "__builtin_mips_addqh_ph",
+    "llvm.mips.addqh.r.ph" => "__builtin_mips_addqh_r_ph",
+    "llvm.mips.addqh.r.w" => "__builtin_mips_addqh_r_w",
+    "llvm.mips.addqh.w" => "__builtin_mips_addqh_w",
+    "llvm.mips.adds.a.b" => "__builtin_msa_adds_a_b",
+    "llvm.mips.adds.a.d" => "__builtin_msa_adds_a_d",
+    "llvm.mips.adds.a.h" => "__builtin_msa_adds_a_h",
+    "llvm.mips.adds.a.w" => "__builtin_msa_adds_a_w",
+    "llvm.mips.adds.s.b" => "__builtin_msa_adds_s_b",
+    "llvm.mips.adds.s.d" => "__builtin_msa_adds_s_d",
+    "llvm.mips.adds.s.h" => "__builtin_msa_adds_s_h",
+    "llvm.mips.adds.s.w" => "__builtin_msa_adds_s_w",
+    "llvm.mips.adds.u.b" => "__builtin_msa_adds_u_b",
+    "llvm.mips.adds.u.d" => "__builtin_msa_adds_u_d",
+    "llvm.mips.adds.u.h" => "__builtin_msa_adds_u_h",
+    "llvm.mips.adds.u.w" => "__builtin_msa_adds_u_w",
+    "llvm.mips.addsc" => "__builtin_mips_addsc",
+    "llvm.mips.addu.ph" => "__builtin_mips_addu_ph",
+    "llvm.mips.addu.qb" => "__builtin_mips_addu_qb",
+    "llvm.mips.addu.s.ph" => "__builtin_mips_addu_s_ph",
+    "llvm.mips.addu.s.qb" => "__builtin_mips_addu_s_qb",
+    "llvm.mips.adduh.qb" => "__builtin_mips_adduh_qb",
+    "llvm.mips.adduh.r.qb" => "__builtin_mips_adduh_r_qb",
+    "llvm.mips.addv.b" => "__builtin_msa_addv_b",
+    "llvm.mips.addv.d" => "__builtin_msa_addv_d",
+    "llvm.mips.addv.h" => "__builtin_msa_addv_h",
+    "llvm.mips.addv.w" => "__builtin_msa_addv_w",
+    "llvm.mips.addvi.b" => "__builtin_msa_addvi_b",
+    "llvm.mips.addvi.d" => "__builtin_msa_addvi_d",
+    "llvm.mips.addvi.h" => "__builtin_msa_addvi_h",
+    "llvm.mips.addvi.w" => "__builtin_msa_addvi_w",
+    "llvm.mips.addwc" => "__builtin_mips_addwc",
+    "llvm.mips.and.v" => "__builtin_msa_and_v",
+    "llvm.mips.andi.b" => "__builtin_msa_andi_b",
+    "llvm.mips.append" => "__builtin_mips_append",
+    "llvm.mips.asub.s.b" => "__builtin_msa_asub_s_b",
+    "llvm.mips.asub.s.d" => "__builtin_msa_asub_s_d",
+    "llvm.mips.asub.s.h" => "__builtin_msa_asub_s_h",
+    "llvm.mips.asub.s.w" => "__builtin_msa_asub_s_w",
+    "llvm.mips.asub.u.b" => "__builtin_msa_asub_u_b",
+    "llvm.mips.asub.u.d" => "__builtin_msa_asub_u_d",
+    "llvm.mips.asub.u.h" => "__builtin_msa_asub_u_h",
+    "llvm.mips.asub.u.w" => "__builtin_msa_asub_u_w",
+    "llvm.mips.ave.s.b" => "__builtin_msa_ave_s_b",
+    "llvm.mips.ave.s.d" => "__builtin_msa_ave_s_d",
+    "llvm.mips.ave.s.h" => "__builtin_msa_ave_s_h",
+    "llvm.mips.ave.s.w" => "__builtin_msa_ave_s_w",
+    "llvm.mips.ave.u.b" => "__builtin_msa_ave_u_b",
+    "llvm.mips.ave.u.d" => "__builtin_msa_ave_u_d",
+    "llvm.mips.ave.u.h" => "__builtin_msa_ave_u_h",
+    "llvm.mips.ave.u.w" => "__builtin_msa_ave_u_w",
+    "llvm.mips.aver.s.b" => "__builtin_msa_aver_s_b",
+    "llvm.mips.aver.s.d" => "__builtin_msa_aver_s_d",
+    "llvm.mips.aver.s.h" => "__builtin_msa_aver_s_h",
+    "llvm.mips.aver.s.w" => "__builtin_msa_aver_s_w",
+    "llvm.mips.aver.u.b" => "__builtin_msa_aver_u_b",
+    "llvm.mips.aver.u.d" => "__builtin_msa_aver_u_d",
+    "llvm.mips.aver.u.h" => "__builtin_msa_aver_u_h",
+    "llvm.mips.aver.u.w" => "__builtin_msa_aver_u_w",
+    "llvm.mips.balign" => "__builtin_mips_balign",
+    "llvm.mips.bclr.b" => "__builtin_msa_bclr_b",
+    "llvm.mips.bclr.d" => "__builtin_msa_bclr_d",
+    "llvm.mips.bclr.h" => "__builtin_msa_bclr_h",
+    "llvm.mips.bclr.w" => "__builtin_msa_bclr_w",
+    "llvm.mips.bclri.b" => "__builtin_msa_bclri_b",
+    "llvm.mips.bclri.d" => "__builtin_msa_bclri_d",
+    "llvm.mips.bclri.h" => "__builtin_msa_bclri_h",
+    "llvm.mips.bclri.w" => "__builtin_msa_bclri_w",
+    "llvm.mips.binsl.b" => "__builtin_msa_binsl_b",
+    "llvm.mips.binsl.d" => "__builtin_msa_binsl_d",
+    "llvm.mips.binsl.h" => "__builtin_msa_binsl_h",
+    "llvm.mips.binsl.w" => "__builtin_msa_binsl_w",
+    "llvm.mips.binsli.b" => "__builtin_msa_binsli_b",
+    "llvm.mips.binsli.d" => "__builtin_msa_binsli_d",
+    "llvm.mips.binsli.h" => "__builtin_msa_binsli_h",
+    "llvm.mips.binsli.w" => "__builtin_msa_binsli_w",
+    "llvm.mips.binsr.b" => "__builtin_msa_binsr_b",
+    "llvm.mips.binsr.d" => "__builtin_msa_binsr_d",
+    "llvm.mips.binsr.h" => "__builtin_msa_binsr_h",
+    "llvm.mips.binsr.w" => "__builtin_msa_binsr_w",
+    "llvm.mips.binsri.b" => "__builtin_msa_binsri_b",
+    "llvm.mips.binsri.d" => "__builtin_msa_binsri_d",
+    "llvm.mips.binsri.h" => "__builtin_msa_binsri_h",
+    "llvm.mips.binsri.w" => "__builtin_msa_binsri_w",
+    "llvm.mips.bitrev" => "__builtin_mips_bitrev",
+    "llvm.mips.bmnz.v" => "__builtin_msa_bmnz_v",
+    "llvm.mips.bmnzi.b" => "__builtin_msa_bmnzi_b",
+    "llvm.mips.bmz.v" => "__builtin_msa_bmz_v",
+    "llvm.mips.bmzi.b" => "__builtin_msa_bmzi_b",
+    "llvm.mips.bneg.b" => "__builtin_msa_bneg_b",
+    "llvm.mips.bneg.d" => "__builtin_msa_bneg_d",
+    "llvm.mips.bneg.h" => "__builtin_msa_bneg_h",
+    "llvm.mips.bneg.w" => "__builtin_msa_bneg_w",
+    "llvm.mips.bnegi.b" => "__builtin_msa_bnegi_b",
+    "llvm.mips.bnegi.d" => "__builtin_msa_bnegi_d",
+    "llvm.mips.bnegi.h" => "__builtin_msa_bnegi_h",
+    "llvm.mips.bnegi.w" => "__builtin_msa_bnegi_w",
+    "llvm.mips.bnz.b" => "__builtin_msa_bnz_b",
+    "llvm.mips.bnz.d" => "__builtin_msa_bnz_d",
+    "llvm.mips.bnz.h" => "__builtin_msa_bnz_h",
+    "llvm.mips.bnz.v" => "__builtin_msa_bnz_v",
+    "llvm.mips.bnz.w" => "__builtin_msa_bnz_w",
+    "llvm.mips.bposge32" => "__builtin_mips_bposge32",
+    "llvm.mips.bsel.v" => "__builtin_msa_bsel_v",
+    "llvm.mips.bseli.b" => "__builtin_msa_bseli_b",
+    "llvm.mips.bset.b" => "__builtin_msa_bset_b",
+    "llvm.mips.bset.d" => "__builtin_msa_bset_d",
+    "llvm.mips.bset.h" => "__builtin_msa_bset_h",
+    "llvm.mips.bset.w" => "__builtin_msa_bset_w",
+    "llvm.mips.bseti.b" => "__builtin_msa_bseti_b",
+    "llvm.mips.bseti.d" => "__builtin_msa_bseti_d",
+    "llvm.mips.bseti.h" => "__builtin_msa_bseti_h",
+    "llvm.mips.bseti.w" => "__builtin_msa_bseti_w",
+    "llvm.mips.bz.b" => "__builtin_msa_bz_b",
+    "llvm.mips.bz.d" => "__builtin_msa_bz_d",
+    "llvm.mips.bz.h" => "__builtin_msa_bz_h",
+    "llvm.mips.bz.v" => "__builtin_msa_bz_v",
+    "llvm.mips.bz.w" => "__builtin_msa_bz_w",
+    "llvm.mips.ceq.b" => "__builtin_msa_ceq_b",
+    "llvm.mips.ceq.d" => "__builtin_msa_ceq_d",
+    "llvm.mips.ceq.h" => "__builtin_msa_ceq_h",
+    "llvm.mips.ceq.w" => "__builtin_msa_ceq_w",
+    "llvm.mips.ceqi.b" => "__builtin_msa_ceqi_b",
+    "llvm.mips.ceqi.d" => "__builtin_msa_ceqi_d",
+    "llvm.mips.ceqi.h" => "__builtin_msa_ceqi_h",
+    "llvm.mips.ceqi.w" => "__builtin_msa_ceqi_w",
+    "llvm.mips.cfcmsa" => "__builtin_msa_cfcmsa",
+    "llvm.mips.cle.s.b" => "__builtin_msa_cle_s_b",
+    "llvm.mips.cle.s.d" => "__builtin_msa_cle_s_d",
+    "llvm.mips.cle.s.h" => "__builtin_msa_cle_s_h",
+    "llvm.mips.cle.s.w" => "__builtin_msa_cle_s_w",
+    "llvm.mips.cle.u.b" => "__builtin_msa_cle_u_b",
+    "llvm.mips.cle.u.d" => "__builtin_msa_cle_u_d",
+    "llvm.mips.cle.u.h" => "__builtin_msa_cle_u_h",
+    "llvm.mips.cle.u.w" => "__builtin_msa_cle_u_w",
+    "llvm.mips.clei.s.b" => "__builtin_msa_clei_s_b",
+    "llvm.mips.clei.s.d" => "__builtin_msa_clei_s_d",
+    "llvm.mips.clei.s.h" => "__builtin_msa_clei_s_h",
+    "llvm.mips.clei.s.w" => "__builtin_msa_clei_s_w",
+    "llvm.mips.clei.u.b" => "__builtin_msa_clei_u_b",
+    "llvm.mips.clei.u.d" => "__builtin_msa_clei_u_d",
+    "llvm.mips.clei.u.h" => "__builtin_msa_clei_u_h",
+    "llvm.mips.clei.u.w" => "__builtin_msa_clei_u_w",
+    "llvm.mips.clt.s.b" => "__builtin_msa_clt_s_b",
+    "llvm.mips.clt.s.d" => "__builtin_msa_clt_s_d",
+    "llvm.mips.clt.s.h" => "__builtin_msa_clt_s_h",
+    "llvm.mips.clt.s.w" => "__builtin_msa_clt_s_w",
+    "llvm.mips.clt.u.b" => "__builtin_msa_clt_u_b",
+    "llvm.mips.clt.u.d" => "__builtin_msa_clt_u_d",
+    "llvm.mips.clt.u.h" => "__builtin_msa_clt_u_h",
+    "llvm.mips.clt.u.w" => "__builtin_msa_clt_u_w",
+    "llvm.mips.clti.s.b" => "__builtin_msa_clti_s_b",
+    "llvm.mips.clti.s.d" => "__builtin_msa_clti_s_d",
+    "llvm.mips.clti.s.h" => "__builtin_msa_clti_s_h",
+    "llvm.mips.clti.s.w" => "__builtin_msa_clti_s_w",
+    "llvm.mips.clti.u.b" => "__builtin_msa_clti_u_b",
+    "llvm.mips.clti.u.d" => "__builtin_msa_clti_u_d",
+    "llvm.mips.clti.u.h" => "__builtin_msa_clti_u_h",
+    "llvm.mips.clti.u.w" => "__builtin_msa_clti_u_w",
+    "llvm.mips.cmp.eq.ph" => "__builtin_mips_cmp_eq_ph",
+    "llvm.mips.cmp.le.ph" => "__builtin_mips_cmp_le_ph",
+    "llvm.mips.cmp.lt.ph" => "__builtin_mips_cmp_lt_ph",
+    "llvm.mips.cmpgdu.eq.qb" => "__builtin_mips_cmpgdu_eq_qb",
+    "llvm.mips.cmpgdu.le.qb" => "__builtin_mips_cmpgdu_le_qb",
+    "llvm.mips.cmpgdu.lt.qb" => "__builtin_mips_cmpgdu_lt_qb",
+    "llvm.mips.cmpgu.eq.qb" => "__builtin_mips_cmpgu_eq_qb",
+    "llvm.mips.cmpgu.le.qb" => "__builtin_mips_cmpgu_le_qb",
+    "llvm.mips.cmpgu.lt.qb" => "__builtin_mips_cmpgu_lt_qb",
+    "llvm.mips.cmpu.eq.qb" => "__builtin_mips_cmpu_eq_qb",
+    "llvm.mips.cmpu.le.qb" => "__builtin_mips_cmpu_le_qb",
+    "llvm.mips.cmpu.lt.qb" => "__builtin_mips_cmpu_lt_qb",
+    "llvm.mips.copy.s.b" => "__builtin_msa_copy_s_b",
+    "llvm.mips.copy.s.d" => "__builtin_msa_copy_s_d",
+    "llvm.mips.copy.s.h" => "__builtin_msa_copy_s_h",
+    "llvm.mips.copy.s.w" => "__builtin_msa_copy_s_w",
+    "llvm.mips.copy.u.b" => "__builtin_msa_copy_u_b",
+    "llvm.mips.copy.u.d" => "__builtin_msa_copy_u_d",
+    "llvm.mips.copy.u.h" => "__builtin_msa_copy_u_h",
+    "llvm.mips.copy.u.w" => "__builtin_msa_copy_u_w",
+    "llvm.mips.ctcmsa" => "__builtin_msa_ctcmsa",
+    "llvm.mips.div.s.b" => "__builtin_msa_div_s_b",
+    "llvm.mips.div.s.d" => "__builtin_msa_div_s_d",
+    "llvm.mips.div.s.h" => "__builtin_msa_div_s_h",
+    "llvm.mips.div.s.w" => "__builtin_msa_div_s_w",
+    "llvm.mips.div.u.b" => "__builtin_msa_div_u_b",
+    "llvm.mips.div.u.d" => "__builtin_msa_div_u_d",
+    "llvm.mips.div.u.h" => "__builtin_msa_div_u_h",
+    "llvm.mips.div.u.w" => "__builtin_msa_div_u_w",
+    "llvm.mips.dlsa" => "__builtin_mips_dlsa",
+    "llvm.mips.dotp.s.d" => "__builtin_msa_dotp_s_d",
+    "llvm.mips.dotp.s.h" => "__builtin_msa_dotp_s_h",
+    "llvm.mips.dotp.s.w" => "__builtin_msa_dotp_s_w",
+    "llvm.mips.dotp.u.d" => "__builtin_msa_dotp_u_d",
+    "llvm.mips.dotp.u.h" => "__builtin_msa_dotp_u_h",
+    "llvm.mips.dotp.u.w" => "__builtin_msa_dotp_u_w",
+    "llvm.mips.dpa.w.ph" => "__builtin_mips_dpa_w_ph",
+    "llvm.mips.dpadd.s.d" => "__builtin_msa_dpadd_s_d",
+    "llvm.mips.dpadd.s.h" => "__builtin_msa_dpadd_s_h",
+    "llvm.mips.dpadd.s.w" => "__builtin_msa_dpadd_s_w",
+    "llvm.mips.dpadd.u.d" => "__builtin_msa_dpadd_u_d",
+    "llvm.mips.dpadd.u.h" => "__builtin_msa_dpadd_u_h",
+    "llvm.mips.dpadd.u.w" => "__builtin_msa_dpadd_u_w",
+    "llvm.mips.dpaq.s.w.ph" => "__builtin_mips_dpaq_s_w_ph",
+    "llvm.mips.dpaq.sa.l.w" => "__builtin_mips_dpaq_sa_l_w",
+    "llvm.mips.dpaqx.s.w.ph" => "__builtin_mips_dpaqx_s_w_ph",
+    "llvm.mips.dpaqx.sa.w.ph" => "__builtin_mips_dpaqx_sa_w_ph",
+    "llvm.mips.dpau.h.qbl" => "__builtin_mips_dpau_h_qbl",
+    "llvm.mips.dpau.h.qbr" => "__builtin_mips_dpau_h_qbr",
+    "llvm.mips.dpax.w.ph" => "__builtin_mips_dpax_w_ph",
+    "llvm.mips.dps.w.ph" => "__builtin_mips_dps_w_ph",
+    "llvm.mips.dpsq.s.w.ph" => "__builtin_mips_dpsq_s_w_ph",
+    "llvm.mips.dpsq.sa.l.w" => "__builtin_mips_dpsq_sa_l_w",
+    "llvm.mips.dpsqx.s.w.ph" => "__builtin_mips_dpsqx_s_w_ph",
+    "llvm.mips.dpsqx.sa.w.ph" => "__builtin_mips_dpsqx_sa_w_ph",
+    "llvm.mips.dpsu.h.qbl" => "__builtin_mips_dpsu_h_qbl",
+    "llvm.mips.dpsu.h.qbr" => "__builtin_mips_dpsu_h_qbr",
+    "llvm.mips.dpsub.s.d" => "__builtin_msa_dpsub_s_d",
+    "llvm.mips.dpsub.s.h" => "__builtin_msa_dpsub_s_h",
+    "llvm.mips.dpsub.s.w" => "__builtin_msa_dpsub_s_w",
+    "llvm.mips.dpsub.u.d" => "__builtin_msa_dpsub_u_d",
+    "llvm.mips.dpsub.u.h" => "__builtin_msa_dpsub_u_h",
+    "llvm.mips.dpsub.u.w" => "__builtin_msa_dpsub_u_w",
+    "llvm.mips.dpsx.w.ph" => "__builtin_mips_dpsx_w_ph",
+    "llvm.mips.extp" => "__builtin_mips_extp",
+    "llvm.mips.extpdp" => "__builtin_mips_extpdp",
+    "llvm.mips.extr.r.w" => "__builtin_mips_extr_r_w",
+    "llvm.mips.extr.rs.w" => "__builtin_mips_extr_rs_w",
+    "llvm.mips.extr.s.h" => "__builtin_mips_extr_s_h",
+    "llvm.mips.extr.w" => "__builtin_mips_extr_w",
+    "llvm.mips.fadd.d" => "__builtin_msa_fadd_d",
+    "llvm.mips.fadd.w" => "__builtin_msa_fadd_w",
+    "llvm.mips.fcaf.d" => "__builtin_msa_fcaf_d",
+    "llvm.mips.fcaf.w" => "__builtin_msa_fcaf_w",
+    "llvm.mips.fceq.d" => "__builtin_msa_fceq_d",
+    "llvm.mips.fceq.w" => "__builtin_msa_fceq_w",
+    "llvm.mips.fclass.d" => "__builtin_msa_fclass_d",
+    "llvm.mips.fclass.w" => "__builtin_msa_fclass_w",
+    "llvm.mips.fcle.d" => "__builtin_msa_fcle_d",
+    "llvm.mips.fcle.w" => "__builtin_msa_fcle_w",
+    "llvm.mips.fclt.d" => "__builtin_msa_fclt_d",
+    "llvm.mips.fclt.w" => "__builtin_msa_fclt_w",
+    "llvm.mips.fcne.d" => "__builtin_msa_fcne_d",
+    "llvm.mips.fcne.w" => "__builtin_msa_fcne_w",
+    "llvm.mips.fcor.d" => "__builtin_msa_fcor_d",
+    "llvm.mips.fcor.w" => "__builtin_msa_fcor_w",
+    "llvm.mips.fcueq.d" => "__builtin_msa_fcueq_d",
+    "llvm.mips.fcueq.w" => "__builtin_msa_fcueq_w",
+    "llvm.mips.fcule.d" => "__builtin_msa_fcule_d",
+    "llvm.mips.fcule.w" => "__builtin_msa_fcule_w",
+    "llvm.mips.fcult.d" => "__builtin_msa_fcult_d",
+    "llvm.mips.fcult.w" => "__builtin_msa_fcult_w",
+    "llvm.mips.fcun.d" => "__builtin_msa_fcun_d",
+    "llvm.mips.fcun.w" => "__builtin_msa_fcun_w",
+    "llvm.mips.fcune.d" => "__builtin_msa_fcune_d",
+    "llvm.mips.fcune.w" => "__builtin_msa_fcune_w",
+    "llvm.mips.fdiv.d" => "__builtin_msa_fdiv_d",
+    "llvm.mips.fdiv.w" => "__builtin_msa_fdiv_w",
+    "llvm.mips.fexdo.h" => "__builtin_msa_fexdo_h",
+    "llvm.mips.fexdo.w" => "__builtin_msa_fexdo_w",
+    "llvm.mips.fexp2.d" => "__builtin_msa_fexp2_d",
+    "llvm.mips.fexp2.w" => "__builtin_msa_fexp2_w",
+    "llvm.mips.fexupl.d" => "__builtin_msa_fexupl_d",
+    "llvm.mips.fexupl.w" => "__builtin_msa_fexupl_w",
+    "llvm.mips.fexupr.d" => "__builtin_msa_fexupr_d",
+    "llvm.mips.fexupr.w" => "__builtin_msa_fexupr_w",
+    "llvm.mips.ffint.s.d" => "__builtin_msa_ffint_s_d",
+    "llvm.mips.ffint.s.w" => "__builtin_msa_ffint_s_w",
+    "llvm.mips.ffint.u.d" => "__builtin_msa_ffint_u_d",
+    "llvm.mips.ffint.u.w" => "__builtin_msa_ffint_u_w",
+    "llvm.mips.ffql.d" => "__builtin_msa_ffql_d",
+    "llvm.mips.ffql.w" => "__builtin_msa_ffql_w",
+    "llvm.mips.ffqr.d" => "__builtin_msa_ffqr_d",
+    "llvm.mips.ffqr.w" => "__builtin_msa_ffqr_w",
+    "llvm.mips.fill.b" => "__builtin_msa_fill_b",
+    "llvm.mips.fill.d" => "__builtin_msa_fill_d",
+    "llvm.mips.fill.h" => "__builtin_msa_fill_h",
+    "llvm.mips.fill.w" => "__builtin_msa_fill_w",
+    "llvm.mips.flog2.d" => "__builtin_msa_flog2_d",
+    "llvm.mips.flog2.w" => "__builtin_msa_flog2_w",
+    "llvm.mips.fmadd.d" => "__builtin_msa_fmadd_d",
+    "llvm.mips.fmadd.w" => "__builtin_msa_fmadd_w",
+    "llvm.mips.fmax.a.d" => "__builtin_msa_fmax_a_d",
+    "llvm.mips.fmax.a.w" => "__builtin_msa_fmax_a_w",
+    "llvm.mips.fmax.d" => "__builtin_msa_fmax_d",
+    "llvm.mips.fmax.w" => "__builtin_msa_fmax_w",
+    "llvm.mips.fmin.a.d" => "__builtin_msa_fmin_a_d",
+    "llvm.mips.fmin.a.w" => "__builtin_msa_fmin_a_w",
+    "llvm.mips.fmin.d" => "__builtin_msa_fmin_d",
+    "llvm.mips.fmin.w" => "__builtin_msa_fmin_w",
+    "llvm.mips.fmsub.d" => "__builtin_msa_fmsub_d",
+    "llvm.mips.fmsub.w" => "__builtin_msa_fmsub_w",
+    "llvm.mips.fmul.d" => "__builtin_msa_fmul_d",
+    "llvm.mips.fmul.w" => "__builtin_msa_fmul_w",
+    "llvm.mips.frcp.d" => "__builtin_msa_frcp_d",
+    "llvm.mips.frcp.w" => "__builtin_msa_frcp_w",
+    "llvm.mips.frint.d" => "__builtin_msa_frint_d",
+    "llvm.mips.frint.w" => "__builtin_msa_frint_w",
+    "llvm.mips.frsqrt.d" => "__builtin_msa_frsqrt_d",
+    "llvm.mips.frsqrt.w" => "__builtin_msa_frsqrt_w",
+    "llvm.mips.fsaf.d" => "__builtin_msa_fsaf_d",
+    "llvm.mips.fsaf.w" => "__builtin_msa_fsaf_w",
+    "llvm.mips.fseq.d" => "__builtin_msa_fseq_d",
+    "llvm.mips.fseq.w" => "__builtin_msa_fseq_w",
+    "llvm.mips.fsle.d" => "__builtin_msa_fsle_d",
+    "llvm.mips.fsle.w" => "__builtin_msa_fsle_w",
+    "llvm.mips.fslt.d" => "__builtin_msa_fslt_d",
+    "llvm.mips.fslt.w" => "__builtin_msa_fslt_w",
+    "llvm.mips.fsne.d" => "__builtin_msa_fsne_d",
+    "llvm.mips.fsne.w" => "__builtin_msa_fsne_w",
+    "llvm.mips.fsor.d" => "__builtin_msa_fsor_d",
+    "llvm.mips.fsor.w" => "__builtin_msa_fsor_w",
+    "llvm.mips.fsqrt.d" => "__builtin_msa_fsqrt_d",
+    "llvm.mips.fsqrt.w" => "__builtin_msa_fsqrt_w",
+    "llvm.mips.fsub.d" => "__builtin_msa_fsub_d",
+    "llvm.mips.fsub.w" => "__builtin_msa_fsub_w",
+    "llvm.mips.fsueq.d" => "__builtin_msa_fsueq_d",
+    "llvm.mips.fsueq.w" => "__builtin_msa_fsueq_w",
+    "llvm.mips.fsule.d" => "__builtin_msa_fsule_d",
+    "llvm.mips.fsule.w" => "__builtin_msa_fsule_w",
+    "llvm.mips.fsult.d" => "__builtin_msa_fsult_d",
+    "llvm.mips.fsult.w" => "__builtin_msa_fsult_w",
+    "llvm.mips.fsun.d" => "__builtin_msa_fsun_d",
+    "llvm.mips.fsun.w" => "__builtin_msa_fsun_w",
+    "llvm.mips.fsune.d" => "__builtin_msa_fsune_d",
+    "llvm.mips.fsune.w" => "__builtin_msa_fsune_w",
+    "llvm.mips.ftint.s.d" => "__builtin_msa_ftint_s_d",
+    "llvm.mips.ftint.s.w" => "__builtin_msa_ftint_s_w",
+    "llvm.mips.ftint.u.d" => "__builtin_msa_ftint_u_d",
+    "llvm.mips.ftint.u.w" => "__builtin_msa_ftint_u_w",
+    "llvm.mips.ftq.h" => "__builtin_msa_ftq_h",
+    "llvm.mips.ftq.w" => "__builtin_msa_ftq_w",
+    "llvm.mips.ftrunc.s.d" => "__builtin_msa_ftrunc_s_d",
+    "llvm.mips.ftrunc.s.w" => "__builtin_msa_ftrunc_s_w",
+    "llvm.mips.ftrunc.u.d" => "__builtin_msa_ftrunc_u_d",
+    "llvm.mips.ftrunc.u.w" => "__builtin_msa_ftrunc_u_w",
+    "llvm.mips.hadd.s.d" => "__builtin_msa_hadd_s_d",
+    "llvm.mips.hadd.s.h" => "__builtin_msa_hadd_s_h",
+    "llvm.mips.hadd.s.w" => "__builtin_msa_hadd_s_w",
+    "llvm.mips.hadd.u.d" => "__builtin_msa_hadd_u_d",
+    "llvm.mips.hadd.u.h" => "__builtin_msa_hadd_u_h",
+    "llvm.mips.hadd.u.w" => "__builtin_msa_hadd_u_w",
+    "llvm.mips.hsub.s.d" => "__builtin_msa_hsub_s_d",
+    "llvm.mips.hsub.s.h" => "__builtin_msa_hsub_s_h",
+    "llvm.mips.hsub.s.w" => "__builtin_msa_hsub_s_w",
+    "llvm.mips.hsub.u.d" => "__builtin_msa_hsub_u_d",
+    "llvm.mips.hsub.u.h" => "__builtin_msa_hsub_u_h",
+    "llvm.mips.hsub.u.w" => "__builtin_msa_hsub_u_w",
+    "llvm.mips.ilvev.b" => "__builtin_msa_ilvev_b",
+    "llvm.mips.ilvev.d" => "__builtin_msa_ilvev_d",
+    "llvm.mips.ilvev.h" => "__builtin_msa_ilvev_h",
+    "llvm.mips.ilvev.w" => "__builtin_msa_ilvev_w",
+    "llvm.mips.ilvl.b" => "__builtin_msa_ilvl_b",
+    "llvm.mips.ilvl.d" => "__builtin_msa_ilvl_d",
+    "llvm.mips.ilvl.h" => "__builtin_msa_ilvl_h",
+    "llvm.mips.ilvl.w" => "__builtin_msa_ilvl_w",
+    "llvm.mips.ilvod.b" => "__builtin_msa_ilvod_b",
+    "llvm.mips.ilvod.d" => "__builtin_msa_ilvod_d",
+    "llvm.mips.ilvod.h" => "__builtin_msa_ilvod_h",
+    "llvm.mips.ilvod.w" => "__builtin_msa_ilvod_w",
+    "llvm.mips.ilvr.b" => "__builtin_msa_ilvr_b",
+    "llvm.mips.ilvr.d" => "__builtin_msa_ilvr_d",
+    "llvm.mips.ilvr.h" => "__builtin_msa_ilvr_h",
+    "llvm.mips.ilvr.w" => "__builtin_msa_ilvr_w",
+    "llvm.mips.insert.b" => "__builtin_msa_insert_b",
+    "llvm.mips.insert.d" => "__builtin_msa_insert_d",
+    "llvm.mips.insert.h" => "__builtin_msa_insert_h",
+    "llvm.mips.insert.w" => "__builtin_msa_insert_w",
+    "llvm.mips.insv" => "__builtin_mips_insv",
+    "llvm.mips.insve.b" => "__builtin_msa_insve_b",
+    "llvm.mips.insve.d" => "__builtin_msa_insve_d",
+    "llvm.mips.insve.h" => "__builtin_msa_insve_h",
+    "llvm.mips.insve.w" => "__builtin_msa_insve_w",
+    "llvm.mips.lbux" => "__builtin_mips_lbux",
+    "llvm.mips.ld.b" => "__builtin_msa_ld_b",
+    "llvm.mips.ld.d" => "__builtin_msa_ld_d",
+    "llvm.mips.ld.h" => "__builtin_msa_ld_h",
+    "llvm.mips.ld.w" => "__builtin_msa_ld_w",
+    "llvm.mips.ldi.b" => "__builtin_msa_ldi_b",
+    "llvm.mips.ldi.d" => "__builtin_msa_ldi_d",
+    "llvm.mips.ldi.h" => "__builtin_msa_ldi_h",
+    "llvm.mips.ldi.w" => "__builtin_msa_ldi_w",
+    "llvm.mips.ldr.d" => "__builtin_msa_ldr_d",
+    "llvm.mips.ldr.w" => "__builtin_msa_ldr_w",
+    "llvm.mips.lhx" => "__builtin_mips_lhx",
+    "llvm.mips.lsa" => "__builtin_mips_lsa",
+    "llvm.mips.lwx" => "__builtin_mips_lwx",
+    "llvm.mips.madd" => "__builtin_mips_madd",
+    "llvm.mips.madd.q.h" => "__builtin_msa_madd_q_h",
+    "llvm.mips.madd.q.w" => "__builtin_msa_madd_q_w",
+    "llvm.mips.maddr.q.h" => "__builtin_msa_maddr_q_h",
+    "llvm.mips.maddr.q.w" => "__builtin_msa_maddr_q_w",
+    "llvm.mips.maddu" => "__builtin_mips_maddu",
+    "llvm.mips.maddv.b" => "__builtin_msa_maddv_b",
+    "llvm.mips.maddv.d" => "__builtin_msa_maddv_d",
+    "llvm.mips.maddv.h" => "__builtin_msa_maddv_h",
+    "llvm.mips.maddv.w" => "__builtin_msa_maddv_w",
+    "llvm.mips.maq.s.w.phl" => "__builtin_mips_maq_s_w_phl",
+    "llvm.mips.maq.s.w.phr" => "__builtin_mips_maq_s_w_phr",
+    "llvm.mips.maq.sa.w.phl" => "__builtin_mips_maq_sa_w_phl",
+    "llvm.mips.maq.sa.w.phr" => "__builtin_mips_maq_sa_w_phr",
+    "llvm.mips.max.a.b" => "__builtin_msa_max_a_b",
+    "llvm.mips.max.a.d" => "__builtin_msa_max_a_d",
+    "llvm.mips.max.a.h" => "__builtin_msa_max_a_h",
+    "llvm.mips.max.a.w" => "__builtin_msa_max_a_w",
+    "llvm.mips.max.s.b" => "__builtin_msa_max_s_b",
+    "llvm.mips.max.s.d" => "__builtin_msa_max_s_d",
+    "llvm.mips.max.s.h" => "__builtin_msa_max_s_h",
+    "llvm.mips.max.s.w" => "__builtin_msa_max_s_w",
+    "llvm.mips.max.u.b" => "__builtin_msa_max_u_b",
+    "llvm.mips.max.u.d" => "__builtin_msa_max_u_d",
+    "llvm.mips.max.u.h" => "__builtin_msa_max_u_h",
+    "llvm.mips.max.u.w" => "__builtin_msa_max_u_w",
+    "llvm.mips.maxi.s.b" => "__builtin_msa_maxi_s_b",
+    "llvm.mips.maxi.s.d" => "__builtin_msa_maxi_s_d",
+    "llvm.mips.maxi.s.h" => "__builtin_msa_maxi_s_h",
+    "llvm.mips.maxi.s.w" => "__builtin_msa_maxi_s_w",
+    "llvm.mips.maxi.u.b" => "__builtin_msa_maxi_u_b",
+    "llvm.mips.maxi.u.d" => "__builtin_msa_maxi_u_d",
+    "llvm.mips.maxi.u.h" => "__builtin_msa_maxi_u_h",
+    "llvm.mips.maxi.u.w" => "__builtin_msa_maxi_u_w",
+    "llvm.mips.min.a.b" => "__builtin_msa_min_a_b",
+    "llvm.mips.min.a.d" => "__builtin_msa_min_a_d",
+    "llvm.mips.min.a.h" => "__builtin_msa_min_a_h",
+    "llvm.mips.min.a.w" => "__builtin_msa_min_a_w",
+    "llvm.mips.min.s.b" => "__builtin_msa_min_s_b",
+    "llvm.mips.min.s.d" => "__builtin_msa_min_s_d",
+    "llvm.mips.min.s.h" => "__builtin_msa_min_s_h",
+    "llvm.mips.min.s.w" => "__builtin_msa_min_s_w",
+    "llvm.mips.min.u.b" => "__builtin_msa_min_u_b",
+    "llvm.mips.min.u.d" => "__builtin_msa_min_u_d",
+    "llvm.mips.min.u.h" => "__builtin_msa_min_u_h",
+    "llvm.mips.min.u.w" => "__builtin_msa_min_u_w",
+    "llvm.mips.mini.s.b" => "__builtin_msa_mini_s_b",
+    "llvm.mips.mini.s.d" => "__builtin_msa_mini_s_d",
+    "llvm.mips.mini.s.h" => "__builtin_msa_mini_s_h",
+    "llvm.mips.mini.s.w" => "__builtin_msa_mini_s_w",
+    "llvm.mips.mini.u.b" => "__builtin_msa_mini_u_b",
+    "llvm.mips.mini.u.d" => "__builtin_msa_mini_u_d",
+    "llvm.mips.mini.u.h" => "__builtin_msa_mini_u_h",
+    "llvm.mips.mini.u.w" => "__builtin_msa_mini_u_w",
+    "llvm.mips.mod.s.b" => "__builtin_msa_mod_s_b",
+    "llvm.mips.mod.s.d" => "__builtin_msa_mod_s_d",
+    "llvm.mips.mod.s.h" => "__builtin_msa_mod_s_h",
+    "llvm.mips.mod.s.w" => "__builtin_msa_mod_s_w",
+    "llvm.mips.mod.u.b" => "__builtin_msa_mod_u_b",
+    "llvm.mips.mod.u.d" => "__builtin_msa_mod_u_d",
+    "llvm.mips.mod.u.h" => "__builtin_msa_mod_u_h",
+    "llvm.mips.mod.u.w" => "__builtin_msa_mod_u_w",
+    "llvm.mips.modsub" => "__builtin_mips_modsub",
+    "llvm.mips.move.v" => "__builtin_msa_move_v",
+    "llvm.mips.msub" => "__builtin_mips_msub",
+    "llvm.mips.msub.q.h" => "__builtin_msa_msub_q_h",
+    "llvm.mips.msub.q.w" => "__builtin_msa_msub_q_w",
+    "llvm.mips.msubr.q.h" => "__builtin_msa_msubr_q_h",
+    "llvm.mips.msubr.q.w" => "__builtin_msa_msubr_q_w",
+    "llvm.mips.msubu" => "__builtin_mips_msubu",
+    "llvm.mips.msubv.b" => "__builtin_msa_msubv_b",
+    "llvm.mips.msubv.d" => "__builtin_msa_msubv_d",
+    "llvm.mips.msubv.h" => "__builtin_msa_msubv_h",
+    "llvm.mips.msubv.w" => "__builtin_msa_msubv_w",
+    "llvm.mips.mthlip" => "__builtin_mips_mthlip",
+    "llvm.mips.mul.ph" => "__builtin_mips_mul_ph",
+    "llvm.mips.mul.q.h" => "__builtin_msa_mul_q_h",
+    "llvm.mips.mul.q.w" => "__builtin_msa_mul_q_w",
+    "llvm.mips.mul.s.ph" => "__builtin_mips_mul_s_ph",
+    "llvm.mips.muleq.s.w.phl" => "__builtin_mips_muleq_s_w_phl",
+    "llvm.mips.muleq.s.w.phr" => "__builtin_mips_muleq_s_w_phr",
+    "llvm.mips.muleu.s.ph.qbl" => "__builtin_mips_muleu_s_ph_qbl",
+    "llvm.mips.muleu.s.ph.qbr" => "__builtin_mips_muleu_s_ph_qbr",
+    "llvm.mips.mulq.rs.ph" => "__builtin_mips_mulq_rs_ph",
+    "llvm.mips.mulq.rs.w" => "__builtin_mips_mulq_rs_w",
+    "llvm.mips.mulq.s.ph" => "__builtin_mips_mulq_s_ph",
+    "llvm.mips.mulq.s.w" => "__builtin_mips_mulq_s_w",
+    "llvm.mips.mulr.q.h" => "__builtin_msa_mulr_q_h",
+    "llvm.mips.mulr.q.w" => "__builtin_msa_mulr_q_w",
+    "llvm.mips.mulsa.w.ph" => "__builtin_mips_mulsa_w_ph",
+    "llvm.mips.mulsaq.s.w.ph" => "__builtin_mips_mulsaq_s_w_ph",
+    "llvm.mips.mult" => "__builtin_mips_mult",
+    "llvm.mips.multu" => "__builtin_mips_multu",
+    "llvm.mips.mulv.b" => "__builtin_msa_mulv_b",
+    "llvm.mips.mulv.d" => "__builtin_msa_mulv_d",
+    "llvm.mips.mulv.h" => "__builtin_msa_mulv_h",
+    "llvm.mips.mulv.w" => "__builtin_msa_mulv_w",
+    "llvm.mips.nloc.b" => "__builtin_msa_nloc_b",
+    "llvm.mips.nloc.d" => "__builtin_msa_nloc_d",
+    "llvm.mips.nloc.h" => "__builtin_msa_nloc_h",
+    "llvm.mips.nloc.w" => "__builtin_msa_nloc_w",
+    "llvm.mips.nlzc.b" => "__builtin_msa_nlzc_b",
+    "llvm.mips.nlzc.d" => "__builtin_msa_nlzc_d",
+    "llvm.mips.nlzc.h" => "__builtin_msa_nlzc_h",
+    "llvm.mips.nlzc.w" => "__builtin_msa_nlzc_w",
+    "llvm.mips.nor.v" => "__builtin_msa_nor_v",
+    "llvm.mips.nori.b" => "__builtin_msa_nori_b",
+    "llvm.mips.or.v" => "__builtin_msa_or_v",
+    "llvm.mips.ori.b" => "__builtin_msa_ori_b",
+    "llvm.mips.packrl.ph" => "__builtin_mips_packrl_ph",
+    "llvm.mips.pckev.b" => "__builtin_msa_pckev_b",
+    "llvm.mips.pckev.d" => "__builtin_msa_pckev_d",
+    "llvm.mips.pckev.h" => "__builtin_msa_pckev_h",
+    "llvm.mips.pckev.w" => "__builtin_msa_pckev_w",
+    "llvm.mips.pckod.b" => "__builtin_msa_pckod_b",
+    "llvm.mips.pckod.d" => "__builtin_msa_pckod_d",
+    "llvm.mips.pckod.h" => "__builtin_msa_pckod_h",
+    "llvm.mips.pckod.w" => "__builtin_msa_pckod_w",
+    "llvm.mips.pcnt.b" => "__builtin_msa_pcnt_b",
+    "llvm.mips.pcnt.d" => "__builtin_msa_pcnt_d",
+    "llvm.mips.pcnt.h" => "__builtin_msa_pcnt_h",
+    "llvm.mips.pcnt.w" => "__builtin_msa_pcnt_w",
+    "llvm.mips.pick.ph" => "__builtin_mips_pick_ph",
+    "llvm.mips.pick.qb" => "__builtin_mips_pick_qb",
+    "llvm.mips.preceq.w.phl" => "__builtin_mips_preceq_w_phl",
+    "llvm.mips.preceq.w.phr" => "__builtin_mips_preceq_w_phr",
+    "llvm.mips.precequ.ph.qbl" => "__builtin_mips_precequ_ph_qbl",
+    "llvm.mips.precequ.ph.qbla" => "__builtin_mips_precequ_ph_qbla",
+    "llvm.mips.precequ.ph.qbr" => "__builtin_mips_precequ_ph_qbr",
+    "llvm.mips.precequ.ph.qbra" => "__builtin_mips_precequ_ph_qbra",
+    "llvm.mips.preceu.ph.qbl" => "__builtin_mips_preceu_ph_qbl",
+    "llvm.mips.preceu.ph.qbla" => "__builtin_mips_preceu_ph_qbla",
+    "llvm.mips.preceu.ph.qbr" => "__builtin_mips_preceu_ph_qbr",
+    "llvm.mips.preceu.ph.qbra" => "__builtin_mips_preceu_ph_qbra",
+    "llvm.mips.precr.qb.ph" => "__builtin_mips_precr_qb_ph",
+    "llvm.mips.precr.sra.ph.w" => "__builtin_mips_precr_sra_ph_w",
+    "llvm.mips.precr.sra.r.ph.w" => "__builtin_mips_precr_sra_r_ph_w",
+    "llvm.mips.precrq.ph.w" => "__builtin_mips_precrq_ph_w",
+    "llvm.mips.precrq.qb.ph" => "__builtin_mips_precrq_qb_ph",
+    "llvm.mips.precrq.rs.ph.w" => "__builtin_mips_precrq_rs_ph_w",
+    "llvm.mips.precrqu.s.qb.ph" => "__builtin_mips_precrqu_s_qb_ph",
+    "llvm.mips.prepend" => "__builtin_mips_prepend",
+    "llvm.mips.raddu.w.qb" => "__builtin_mips_raddu_w_qb",
+    "llvm.mips.rddsp" => "__builtin_mips_rddsp",
+    "llvm.mips.repl.ph" => "__builtin_mips_repl_ph",
+    "llvm.mips.repl.qb" => "__builtin_mips_repl_qb",
+    "llvm.mips.sat.s.b" => "__builtin_msa_sat_s_b",
+    "llvm.mips.sat.s.d" => "__builtin_msa_sat_s_d",
+    "llvm.mips.sat.s.h" => "__builtin_msa_sat_s_h",
+    "llvm.mips.sat.s.w" => "__builtin_msa_sat_s_w",
+    "llvm.mips.sat.u.b" => "__builtin_msa_sat_u_b",
+    "llvm.mips.sat.u.d" => "__builtin_msa_sat_u_d",
+    "llvm.mips.sat.u.h" => "__builtin_msa_sat_u_h",
+    "llvm.mips.sat.u.w" => "__builtin_msa_sat_u_w",
+    "llvm.mips.shf.b" => "__builtin_msa_shf_b",
+    "llvm.mips.shf.h" => "__builtin_msa_shf_h",
+    "llvm.mips.shf.w" => "__builtin_msa_shf_w",
+    "llvm.mips.shilo" => "__builtin_mips_shilo",
+    "llvm.mips.shll.ph" => "__builtin_mips_shll_ph",
+    "llvm.mips.shll.qb" => "__builtin_mips_shll_qb",
+    "llvm.mips.shll.s.ph" => "__builtin_mips_shll_s_ph",
+    "llvm.mips.shll.s.w" => "__builtin_mips_shll_s_w",
+    "llvm.mips.shra.ph" => "__builtin_mips_shra_ph",
+    "llvm.mips.shra.qb" => "__builtin_mips_shra_qb",
+    "llvm.mips.shra.r.ph" => "__builtin_mips_shra_r_ph",
+    "llvm.mips.shra.r.qb" => "__builtin_mips_shra_r_qb",
+    "llvm.mips.shra.r.w" => "__builtin_mips_shra_r_w",
+    "llvm.mips.shrl.ph" => "__builtin_mips_shrl_ph",
+    "llvm.mips.shrl.qb" => "__builtin_mips_shrl_qb",
+    "llvm.mips.sld.b" => "__builtin_msa_sld_b",
+    "llvm.mips.sld.d" => "__builtin_msa_sld_d",
+    "llvm.mips.sld.h" => "__builtin_msa_sld_h",
+    "llvm.mips.sld.w" => "__builtin_msa_sld_w",
+    "llvm.mips.sldi.b" => "__builtin_msa_sldi_b",
+    "llvm.mips.sldi.d" => "__builtin_msa_sldi_d",
+    "llvm.mips.sldi.h" => "__builtin_msa_sldi_h",
+    "llvm.mips.sldi.w" => "__builtin_msa_sldi_w",
+    "llvm.mips.sll.b" => "__builtin_msa_sll_b",
+    "llvm.mips.sll.d" => "__builtin_msa_sll_d",
+    "llvm.mips.sll.h" => "__builtin_msa_sll_h",
+    "llvm.mips.sll.w" => "__builtin_msa_sll_w",
+    "llvm.mips.slli.b" => "__builtin_msa_slli_b",
+    "llvm.mips.slli.d" => "__builtin_msa_slli_d",
+    "llvm.mips.slli.h" => "__builtin_msa_slli_h",
+    "llvm.mips.slli.w" => "__builtin_msa_slli_w",
+    "llvm.mips.splat.b" => "__builtin_msa_splat_b",
+    "llvm.mips.splat.d" => "__builtin_msa_splat_d",
+    "llvm.mips.splat.h" => "__builtin_msa_splat_h",
+    "llvm.mips.splat.w" => "__builtin_msa_splat_w",
+    "llvm.mips.splati.b" => "__builtin_msa_splati_b",
+    "llvm.mips.splati.d" => "__builtin_msa_splati_d",
+    "llvm.mips.splati.h" => "__builtin_msa_splati_h",
+    "llvm.mips.splati.w" => "__builtin_msa_splati_w",
+    "llvm.mips.sra.b" => "__builtin_msa_sra_b",
+    "llvm.mips.sra.d" => "__builtin_msa_sra_d",
+    "llvm.mips.sra.h" => "__builtin_msa_sra_h",
+    "llvm.mips.sra.w" => "__builtin_msa_sra_w",
+    "llvm.mips.srai.b" => "__builtin_msa_srai_b",
+    "llvm.mips.srai.d" => "__builtin_msa_srai_d",
+    "llvm.mips.srai.h" => "__builtin_msa_srai_h",
+    "llvm.mips.srai.w" => "__builtin_msa_srai_w",
+    "llvm.mips.srar.b" => "__builtin_msa_srar_b",
+    "llvm.mips.srar.d" => "__builtin_msa_srar_d",
+    "llvm.mips.srar.h" => "__builtin_msa_srar_h",
+    "llvm.mips.srar.w" => "__builtin_msa_srar_w",
+    "llvm.mips.srari.b" => "__builtin_msa_srari_b",
+    "llvm.mips.srari.d" => "__builtin_msa_srari_d",
+    "llvm.mips.srari.h" => "__builtin_msa_srari_h",
+    "llvm.mips.srari.w" => "__builtin_msa_srari_w",
+    "llvm.mips.srl.b" => "__builtin_msa_srl_b",
+    "llvm.mips.srl.d" => "__builtin_msa_srl_d",
+    "llvm.mips.srl.h" => "__builtin_msa_srl_h",
+    "llvm.mips.srl.w" => "__builtin_msa_srl_w",
+    "llvm.mips.srli.b" => "__builtin_msa_srli_b",
+    "llvm.mips.srli.d" => "__builtin_msa_srli_d",
+    "llvm.mips.srli.h" => "__builtin_msa_srli_h",
+    "llvm.mips.srli.w" => "__builtin_msa_srli_w",
+    "llvm.mips.srlr.b" => "__builtin_msa_srlr_b",
+    "llvm.mips.srlr.d" => "__builtin_msa_srlr_d",
+    "llvm.mips.srlr.h" => "__builtin_msa_srlr_h",
+    "llvm.mips.srlr.w" => "__builtin_msa_srlr_w",
+    "llvm.mips.srlri.b" => "__builtin_msa_srlri_b",
+    "llvm.mips.srlri.d" => "__builtin_msa_srlri_d",
+    "llvm.mips.srlri.h" => "__builtin_msa_srlri_h",
+    "llvm.mips.srlri.w" => "__builtin_msa_srlri_w",
+    "llvm.mips.st.b" => "__builtin_msa_st_b",
+    "llvm.mips.st.d" => "__builtin_msa_st_d",
+    "llvm.mips.st.h" => "__builtin_msa_st_h",
+    "llvm.mips.st.w" => "__builtin_msa_st_w",
+    "llvm.mips.str.d" => "__builtin_msa_str_d",
+    "llvm.mips.str.w" => "__builtin_msa_str_w",
+    "llvm.mips.subq.ph" => "__builtin_mips_subq_ph",
+    "llvm.mips.subq.s.ph" => "__builtin_mips_subq_s_ph",
+    "llvm.mips.subq.s.w" => "__builtin_mips_subq_s_w",
+    "llvm.mips.subqh.ph" => "__builtin_mips_subqh_ph",
+    "llvm.mips.subqh.r.ph" => "__builtin_mips_subqh_r_ph",
+    "llvm.mips.subqh.r.w" => "__builtin_mips_subqh_r_w",
+    "llvm.mips.subqh.w" => "__builtin_mips_subqh_w",
+    "llvm.mips.subs.s.b" => "__builtin_msa_subs_s_b",
+    "llvm.mips.subs.s.d" => "__builtin_msa_subs_s_d",
+    "llvm.mips.subs.s.h" => "__builtin_msa_subs_s_h",
+    "llvm.mips.subs.s.w" => "__builtin_msa_subs_s_w",
+    "llvm.mips.subs.u.b" => "__builtin_msa_subs_u_b",
+    "llvm.mips.subs.u.d" => "__builtin_msa_subs_u_d",
+    "llvm.mips.subs.u.h" => "__builtin_msa_subs_u_h",
+    "llvm.mips.subs.u.w" => "__builtin_msa_subs_u_w",
+    "llvm.mips.subsus.u.b" => "__builtin_msa_subsus_u_b",
+    "llvm.mips.subsus.u.d" => "__builtin_msa_subsus_u_d",
+    "llvm.mips.subsus.u.h" => "__builtin_msa_subsus_u_h",
+    "llvm.mips.subsus.u.w" => "__builtin_msa_subsus_u_w",
+    "llvm.mips.subsuu.s.b" => "__builtin_msa_subsuu_s_b",
+    "llvm.mips.subsuu.s.d" => "__builtin_msa_subsuu_s_d",
+    "llvm.mips.subsuu.s.h" => "__builtin_msa_subsuu_s_h",
+    "llvm.mips.subsuu.s.w" => "__builtin_msa_subsuu_s_w",
+    "llvm.mips.subu.ph" => "__builtin_mips_subu_ph",
+    "llvm.mips.subu.qb" => "__builtin_mips_subu_qb",
+    "llvm.mips.subu.s.ph" => "__builtin_mips_subu_s_ph",
+    "llvm.mips.subu.s.qb" => "__builtin_mips_subu_s_qb",
+    "llvm.mips.subuh.qb" => "__builtin_mips_subuh_qb",
+    "llvm.mips.subuh.r.qb" => "__builtin_mips_subuh_r_qb",
+    "llvm.mips.subv.b" => "__builtin_msa_subv_b",
+    "llvm.mips.subv.d" => "__builtin_msa_subv_d",
+    "llvm.mips.subv.h" => "__builtin_msa_subv_h",
+    "llvm.mips.subv.w" => "__builtin_msa_subv_w",
+    "llvm.mips.subvi.b" => "__builtin_msa_subvi_b",
+    "llvm.mips.subvi.d" => "__builtin_msa_subvi_d",
+    "llvm.mips.subvi.h" => "__builtin_msa_subvi_h",
+    "llvm.mips.subvi.w" => "__builtin_msa_subvi_w",
+    "llvm.mips.vshf.b" => "__builtin_msa_vshf_b",
+    "llvm.mips.vshf.d" => "__builtin_msa_vshf_d",
+    "llvm.mips.vshf.h" => "__builtin_msa_vshf_h",
+    "llvm.mips.vshf.w" => "__builtin_msa_vshf_w",
+    "llvm.mips.wrdsp" => "__builtin_mips_wrdsp",
+    "llvm.mips.xor.v" => "__builtin_msa_xor_v",
+    "llvm.mips.xori.b" => "__builtin_msa_xori_b",
+    // nvvm
+    "llvm.nvvm.abs.i" => "__nvvm_abs_i",
+    "llvm.nvvm.abs.ll" => "__nvvm_abs_ll",
+    "llvm.nvvm.add.rm.d" => "__nvvm_add_rm_d",
+    "llvm.nvvm.add.rm.f" => "__nvvm_add_rm_f",
+    "llvm.nvvm.add.rm.ftz.f" => "__nvvm_add_rm_ftz_f",
+    "llvm.nvvm.add.rn.d" => "__nvvm_add_rn_d",
+    "llvm.nvvm.add.rn.f" => "__nvvm_add_rn_f",
+    "llvm.nvvm.add.rn.ftz.f" => "__nvvm_add_rn_ftz_f",
+    "llvm.nvvm.add.rp.d" => "__nvvm_add_rp_d",
+    "llvm.nvvm.add.rp.f" => "__nvvm_add_rp_f",
+    "llvm.nvvm.add.rp.ftz.f" => "__nvvm_add_rp_ftz_f",
+    "llvm.nvvm.add.rz.d" => "__nvvm_add_rz_d",
+    "llvm.nvvm.add.rz.f" => "__nvvm_add_rz_f",
+    "llvm.nvvm.add.rz.ftz.f" => "__nvvm_add_rz_ftz_f",
+    "llvm.nvvm.bar.sync" => "__nvvm_bar_sync",
+    "llvm.nvvm.barrier0" => "__nvvm_bar0",
+    // [DUPLICATE]: "llvm.nvvm.barrier0" => "__syncthreads",
+    "llvm.nvvm.barrier0.and" => "__nvvm_bar0_and",
+    "llvm.nvvm.barrier0.or" => "__nvvm_bar0_or",
+    "llvm.nvvm.barrier0.popc" => "__nvvm_bar0_popc",
+    "llvm.nvvm.bitcast.d2ll" => "__nvvm_bitcast_d2ll",
+    "llvm.nvvm.bitcast.f2i" => "__nvvm_bitcast_f2i",
+    "llvm.nvvm.bitcast.i2f" => "__nvvm_bitcast_i2f",
+    "llvm.nvvm.bitcast.ll2d" => "__nvvm_bitcast_ll2d",
+    "llvm.nvvm.brev32" => "__nvvm_brev32",
+    "llvm.nvvm.brev64" => "__nvvm_brev64",
+    "llvm.nvvm.ceil.d" => "__nvvm_ceil_d",
+    "llvm.nvvm.ceil.f" => "__nvvm_ceil_f",
+    "llvm.nvvm.ceil.ftz.f" => "__nvvm_ceil_ftz_f",
+    "llvm.nvvm.clz.i" => "__nvvm_clz_i",
+    "llvm.nvvm.clz.ll" => "__nvvm_clz_ll",
+    "llvm.nvvm.cos.approx.f" => "__nvvm_cos_approx_f",
+    "llvm.nvvm.cos.approx.ftz.f" => "__nvvm_cos_approx_ftz_f",
+    "llvm.nvvm.d2f.rm" => "__nvvm_d2f_rm",
+    "llvm.nvvm.d2f.rm.ftz" => "__nvvm_d2f_rm_ftz",
+    "llvm.nvvm.d2f.rn" => "__nvvm_d2f_rn",
+    "llvm.nvvm.d2f.rn.ftz" => "__nvvm_d2f_rn_ftz",
+    "llvm.nvvm.d2f.rp" => "__nvvm_d2f_rp",
+    "llvm.nvvm.d2f.rp.ftz" => "__nvvm_d2f_rp_ftz",
+    "llvm.nvvm.d2f.rz" => "__nvvm_d2f_rz",
+    "llvm.nvvm.d2f.rz.ftz" => "__nvvm_d2f_rz_ftz",
+    "llvm.nvvm.d2i.hi" => "__nvvm_d2i_hi",
+    "llvm.nvvm.d2i.lo" => "__nvvm_d2i_lo",
+    "llvm.nvvm.d2i.rm" => "__nvvm_d2i_rm",
+    "llvm.nvvm.d2i.rn" => "__nvvm_d2i_rn",
+    "llvm.nvvm.d2i.rp" => "__nvvm_d2i_rp",
+    "llvm.nvvm.d2i.rz" => "__nvvm_d2i_rz",
+    "llvm.nvvm.d2ll.rm" => "__nvvm_d2ll_rm",
+    "llvm.nvvm.d2ll.rn" => "__nvvm_d2ll_rn",
+    "llvm.nvvm.d2ll.rp" => "__nvvm_d2ll_rp",
+    "llvm.nvvm.d2ll.rz" => "__nvvm_d2ll_rz",
+    "llvm.nvvm.d2ui.rm" => "__nvvm_d2ui_rm",
+    "llvm.nvvm.d2ui.rn" => "__nvvm_d2ui_rn",
+    "llvm.nvvm.d2ui.rp" => "__nvvm_d2ui_rp",
+    "llvm.nvvm.d2ui.rz" => "__nvvm_d2ui_rz",
+    "llvm.nvvm.d2ull.rm" => "__nvvm_d2ull_rm",
+    "llvm.nvvm.d2ull.rn" => "__nvvm_d2ull_rn",
+    "llvm.nvvm.d2ull.rp" => "__nvvm_d2ull_rp",
+    "llvm.nvvm.d2ull.rz" => "__nvvm_d2ull_rz",
+    "llvm.nvvm.div.approx.f" => "__nvvm_div_approx_f",
+    "llvm.nvvm.div.approx.ftz.f" => "__nvvm_div_approx_ftz_f",
+    "llvm.nvvm.div.rm.d" => "__nvvm_div_rm_d",
+    "llvm.nvvm.div.rm.f" => "__nvvm_div_rm_f",
+    "llvm.nvvm.div.rm.ftz.f" => "__nvvm_div_rm_ftz_f",
+    "llvm.nvvm.div.rn.d" => "__nvvm_div_rn_d",
+    "llvm.nvvm.div.rn.f" => "__nvvm_div_rn_f",
+    "llvm.nvvm.div.rn.ftz.f" => "__nvvm_div_rn_ftz_f",
+    "llvm.nvvm.div.rp.d" => "__nvvm_div_rp_d",
+    "llvm.nvvm.div.rp.f" => "__nvvm_div_rp_f",
+    "llvm.nvvm.div.rp.ftz.f" => "__nvvm_div_rp_ftz_f",
+    "llvm.nvvm.div.rz.d" => "__nvvm_div_rz_d",
+    "llvm.nvvm.div.rz.f" => "__nvvm_div_rz_f",
+    "llvm.nvvm.div.rz.ftz.f" => "__nvvm_div_rz_ftz_f",
+    "llvm.nvvm.ex2.approx.d" => "__nvvm_ex2_approx_d",
+    "llvm.nvvm.ex2.approx.f" => "__nvvm_ex2_approx_f",
+    "llvm.nvvm.ex2.approx.ftz.f" => "__nvvm_ex2_approx_ftz_f",
+    "llvm.nvvm.f2h.rn" => "__nvvm_f2h_rn",
+    "llvm.nvvm.f2h.rn.ftz" => "__nvvm_f2h_rn_ftz",
+    "llvm.nvvm.f2i.rm" => "__nvvm_f2i_rm",
+    "llvm.nvvm.f2i.rm.ftz" => "__nvvm_f2i_rm_ftz",
+    "llvm.nvvm.f2i.rn" => "__nvvm_f2i_rn",
+    "llvm.nvvm.f2i.rn.ftz" => "__nvvm_f2i_rn_ftz",
+    "llvm.nvvm.f2i.rp" => "__nvvm_f2i_rp",
+    "llvm.nvvm.f2i.rp.ftz" => "__nvvm_f2i_rp_ftz",
+    "llvm.nvvm.f2i.rz" => "__nvvm_f2i_rz",
+    "llvm.nvvm.f2i.rz.ftz" => "__nvvm_f2i_rz_ftz",
+    "llvm.nvvm.f2ll.rm" => "__nvvm_f2ll_rm",
+    "llvm.nvvm.f2ll.rm.ftz" => "__nvvm_f2ll_rm_ftz",
+    "llvm.nvvm.f2ll.rn" => "__nvvm_f2ll_rn",
+    "llvm.nvvm.f2ll.rn.ftz" => "__nvvm_f2ll_rn_ftz",
+    "llvm.nvvm.f2ll.rp" => "__nvvm_f2ll_rp",
+    "llvm.nvvm.f2ll.rp.ftz" => "__nvvm_f2ll_rp_ftz",
+    "llvm.nvvm.f2ll.rz" => "__nvvm_f2ll_rz",
+    "llvm.nvvm.f2ll.rz.ftz" => "__nvvm_f2ll_rz_ftz",
+    "llvm.nvvm.f2ui.rm" => "__nvvm_f2ui_rm",
+    "llvm.nvvm.f2ui.rm.ftz" => "__nvvm_f2ui_rm_ftz",
+    "llvm.nvvm.f2ui.rn" => "__nvvm_f2ui_rn",
+    "llvm.nvvm.f2ui.rn.ftz" => "__nvvm_f2ui_rn_ftz",
+    "llvm.nvvm.f2ui.rp" => "__nvvm_f2ui_rp",
+    "llvm.nvvm.f2ui.rp.ftz" => "__nvvm_f2ui_rp_ftz",
+    "llvm.nvvm.f2ui.rz" => "__nvvm_f2ui_rz",
+    "llvm.nvvm.f2ui.rz.ftz" => "__nvvm_f2ui_rz_ftz",
+    "llvm.nvvm.f2ull.rm" => "__nvvm_f2ull_rm",
+    "llvm.nvvm.f2ull.rm.ftz" => "__nvvm_f2ull_rm_ftz",
+    "llvm.nvvm.f2ull.rn" => "__nvvm_f2ull_rn",
+    "llvm.nvvm.f2ull.rn.ftz" => "__nvvm_f2ull_rn_ftz",
+    "llvm.nvvm.f2ull.rp" => "__nvvm_f2ull_rp",
+    "llvm.nvvm.f2ull.rp.ftz" => "__nvvm_f2ull_rp_ftz",
+    "llvm.nvvm.f2ull.rz" => "__nvvm_f2ull_rz",
+    "llvm.nvvm.f2ull.rz.ftz" => "__nvvm_f2ull_rz_ftz",
+    "llvm.nvvm.fabs.d" => "__nvvm_fabs_d",
+    "llvm.nvvm.fabs.f" => "__nvvm_fabs_f",
+    "llvm.nvvm.fabs.ftz.f" => "__nvvm_fabs_ftz_f",
+    "llvm.nvvm.floor.d" => "__nvvm_floor_d",
+    "llvm.nvvm.floor.f" => "__nvvm_floor_f",
+    "llvm.nvvm.floor.ftz.f" => "__nvvm_floor_ftz_f",
+    "llvm.nvvm.fma.rm.d" => "__nvvm_fma_rm_d",
+    "llvm.nvvm.fma.rm.f" => "__nvvm_fma_rm_f",
+    "llvm.nvvm.fma.rm.ftz.f" => "__nvvm_fma_rm_ftz_f",
+    "llvm.nvvm.fma.rn.d" => "__nvvm_fma_rn_d",
+    "llvm.nvvm.fma.rn.f" => "__nvvm_fma_rn_f",
+    "llvm.nvvm.fma.rn.ftz.f" => "__nvvm_fma_rn_ftz_f",
+    "llvm.nvvm.fma.rp.d" => "__nvvm_fma_rp_d",
+    "llvm.nvvm.fma.rp.f" => "__nvvm_fma_rp_f",
+    "llvm.nvvm.fma.rp.ftz.f" => "__nvvm_fma_rp_ftz_f",
+    "llvm.nvvm.fma.rz.d" => "__nvvm_fma_rz_d",
+    "llvm.nvvm.fma.rz.f" => "__nvvm_fma_rz_f",
+    "llvm.nvvm.fma.rz.ftz.f" => "__nvvm_fma_rz_ftz_f",
+    "llvm.nvvm.fmax.d" => "__nvvm_fmax_d",
+    "llvm.nvvm.fmax.f" => "__nvvm_fmax_f",
+    "llvm.nvvm.fmax.ftz.f" => "__nvvm_fmax_ftz_f",
+    "llvm.nvvm.fmin.d" => "__nvvm_fmin_d",
+    "llvm.nvvm.fmin.f" => "__nvvm_fmin_f",
+    "llvm.nvvm.fmin.ftz.f" => "__nvvm_fmin_ftz_f",
+    "llvm.nvvm.h2f" => "__nvvm_h2f",
+    "llvm.nvvm.i2d.rm" => "__nvvm_i2d_rm",
+    "llvm.nvvm.i2d.rn" => "__nvvm_i2d_rn",
+    "llvm.nvvm.i2d.rp" => "__nvvm_i2d_rp",
+    "llvm.nvvm.i2d.rz" => "__nvvm_i2d_rz",
+    "llvm.nvvm.i2f.rm" => "__nvvm_i2f_rm",
+    "llvm.nvvm.i2f.rn" => "__nvvm_i2f_rn",
+    "llvm.nvvm.i2f.rp" => "__nvvm_i2f_rp",
+    "llvm.nvvm.i2f.rz" => "__nvvm_i2f_rz",
+    "llvm.nvvm.isspacep.const" => "__nvvm_isspacep_const",
+    "llvm.nvvm.isspacep.global" => "__nvvm_isspacep_global",
+    "llvm.nvvm.isspacep.local" => "__nvvm_isspacep_local",
+    "llvm.nvvm.isspacep.shared" => "__nvvm_isspacep_shared",
+    "llvm.nvvm.istypep.sampler" => "__nvvm_istypep_sampler",
+    "llvm.nvvm.istypep.surface" => "__nvvm_istypep_surface",
+    "llvm.nvvm.istypep.texture" => "__nvvm_istypep_texture",
+    "llvm.nvvm.lg2.approx.d" => "__nvvm_lg2_approx_d",
+    "llvm.nvvm.lg2.approx.f" => "__nvvm_lg2_approx_f",
+    "llvm.nvvm.lg2.approx.ftz.f" => "__nvvm_lg2_approx_ftz_f",
+    "llvm.nvvm.ll2d.rm" => "__nvvm_ll2d_rm",
+    "llvm.nvvm.ll2d.rn" => "__nvvm_ll2d_rn",
+    "llvm.nvvm.ll2d.rp" => "__nvvm_ll2d_rp",
+    "llvm.nvvm.ll2d.rz" => "__nvvm_ll2d_rz",
+    "llvm.nvvm.ll2f.rm" => "__nvvm_ll2f_rm",
+    "llvm.nvvm.ll2f.rn" => "__nvvm_ll2f_rn",
+    "llvm.nvvm.ll2f.rp" => "__nvvm_ll2f_rp",
+    "llvm.nvvm.ll2f.rz" => "__nvvm_ll2f_rz",
+    "llvm.nvvm.lohi.i2d" => "__nvvm_lohi_i2d",
+    "llvm.nvvm.max.i" => "__nvvm_max_i",
+    "llvm.nvvm.max.ll" => "__nvvm_max_ll",
+    "llvm.nvvm.max.ui" => "__nvvm_max_ui",
+    "llvm.nvvm.max.ull" => "__nvvm_max_ull",
+    "llvm.nvvm.membar.cta" => "__nvvm_membar_cta",
+    "llvm.nvvm.membar.gl" => "__nvvm_membar_gl",
+    "llvm.nvvm.membar.sys" => "__nvvm_membar_sys",
+    "llvm.nvvm.min.i" => "__nvvm_min_i",
+    "llvm.nvvm.min.ll" => "__nvvm_min_ll",
+    "llvm.nvvm.min.ui" => "__nvvm_min_ui",
+    "llvm.nvvm.min.ull" => "__nvvm_min_ull",
+    "llvm.nvvm.mul.rm.d" => "__nvvm_mul_rm_d",
+    "llvm.nvvm.mul.rm.f" => "__nvvm_mul_rm_f",
+    "llvm.nvvm.mul.rm.ftz.f" => "__nvvm_mul_rm_ftz_f",
+    "llvm.nvvm.mul.rn.d" => "__nvvm_mul_rn_d",
+    "llvm.nvvm.mul.rn.f" => "__nvvm_mul_rn_f",
+    "llvm.nvvm.mul.rn.ftz.f" => "__nvvm_mul_rn_ftz_f",
+    "llvm.nvvm.mul.rp.d" => "__nvvm_mul_rp_d",
+    "llvm.nvvm.mul.rp.f" => "__nvvm_mul_rp_f",
+    "llvm.nvvm.mul.rp.ftz.f" => "__nvvm_mul_rp_ftz_f",
+    "llvm.nvvm.mul.rz.d" => "__nvvm_mul_rz_d",
+    "llvm.nvvm.mul.rz.f" => "__nvvm_mul_rz_f",
+    "llvm.nvvm.mul.rz.ftz.f" => "__nvvm_mul_rz_ftz_f",
+    "llvm.nvvm.mul24.i" => "__nvvm_mul24_i",
+    "llvm.nvvm.mul24.ui" => "__nvvm_mul24_ui",
+    "llvm.nvvm.mulhi.i" => "__nvvm_mulhi_i",
+    "llvm.nvvm.mulhi.ll" => "__nvvm_mulhi_ll",
+    "llvm.nvvm.mulhi.ui" => "__nvvm_mulhi_ui",
+    "llvm.nvvm.mulhi.ull" => "__nvvm_mulhi_ull",
+    "llvm.nvvm.popc.i" => "__nvvm_popc_i",
+    "llvm.nvvm.popc.ll" => "__nvvm_popc_ll",
+    "llvm.nvvm.prmt" => "__nvvm_prmt",
+    "llvm.nvvm.rcp.approx.ftz.d" => "__nvvm_rcp_approx_ftz_d",
+    "llvm.nvvm.rcp.rm.d" => "__nvvm_rcp_rm_d",
+    "llvm.nvvm.rcp.rm.f" => "__nvvm_rcp_rm_f",
+    "llvm.nvvm.rcp.rm.ftz.f" => "__nvvm_rcp_rm_ftz_f",
+    "llvm.nvvm.rcp.rn.d" => "__nvvm_rcp_rn_d",
+    "llvm.nvvm.rcp.rn.f" => "__nvvm_rcp_rn_f",
+    "llvm.nvvm.rcp.rn.ftz.f" => "__nvvm_rcp_rn_ftz_f",
+    "llvm.nvvm.rcp.rp.d" => "__nvvm_rcp_rp_d",
+    "llvm.nvvm.rcp.rp.f" => "__nvvm_rcp_rp_f",
+    "llvm.nvvm.rcp.rp.ftz.f" => "__nvvm_rcp_rp_ftz_f",
+    "llvm.nvvm.rcp.rz.d" => "__nvvm_rcp_rz_d",
+    "llvm.nvvm.rcp.rz.f" => "__nvvm_rcp_rz_f",
+    "llvm.nvvm.rcp.rz.ftz.f" => "__nvvm_rcp_rz_ftz_f",
+    "llvm.nvvm.read.ptx.sreg.clock" => "__nvvm_read_ptx_sreg_",
+    "llvm.nvvm.read.ptx.sreg.clock64" => "__nvvm_read_ptx_sreg_",
+    "llvm.nvvm.read.ptx.sreg.ctaid.x" => "__nvvm_read_ptx_sreg_ctaid_x",
+    "llvm.nvvm.read.ptx.sreg.ctaid.y" => "__nvvm_read_ptx_sreg_ctaid_y",
+    "llvm.nvvm.read.ptx.sreg.ctaid.z" => "__nvvm_read_ptx_sreg_ctaid_z",
+    "llvm.nvvm.read.ptx.sreg.envreg0" => "__nvvm_read_ptx_sreg_envreg0",
+    "llvm.nvvm.read.ptx.sreg.envreg1" => "__nvvm_read_ptx_sreg_envreg1",
+    "llvm.nvvm.read.ptx.sreg.envreg10" => "__nvvm_read_ptx_sreg_envreg10",
+    "llvm.nvvm.read.ptx.sreg.envreg11" => "__nvvm_read_ptx_sreg_envreg11",
+    "llvm.nvvm.read.ptx.sreg.envreg12" => "__nvvm_read_ptx_sreg_envreg12",
+    "llvm.nvvm.read.ptx.sreg.envreg13" => "__nvvm_read_ptx_sreg_envreg13",
+    "llvm.nvvm.read.ptx.sreg.envreg14" => "__nvvm_read_ptx_sreg_envreg14",
+    "llvm.nvvm.read.ptx.sreg.envreg15" => "__nvvm_read_ptx_sreg_envreg15",
+    "llvm.nvvm.read.ptx.sreg.envreg16" => "__nvvm_read_ptx_sreg_envreg16",
+    "llvm.nvvm.read.ptx.sreg.envreg17" => "__nvvm_read_ptx_sreg_envreg17",
+    "llvm.nvvm.read.ptx.sreg.envreg18" => "__nvvm_read_ptx_sreg_envreg18",
+    "llvm.nvvm.read.ptx.sreg.envreg19" => "__nvvm_read_ptx_sreg_envreg19",
+    "llvm.nvvm.read.ptx.sreg.envreg2" => "__nvvm_read_ptx_sreg_envreg2",
+    "llvm.nvvm.read.ptx.sreg.envreg20" => "__nvvm_read_ptx_sreg_envreg20",
+    "llvm.nvvm.read.ptx.sreg.envreg21" => "__nvvm_read_ptx_sreg_envreg21",
+    "llvm.nvvm.read.ptx.sreg.envreg22" => "__nvvm_read_ptx_sreg_envreg22",
+    "llvm.nvvm.read.ptx.sreg.envreg23" => "__nvvm_read_ptx_sreg_envreg23",
+    "llvm.nvvm.read.ptx.sreg.envreg24" => "__nvvm_read_ptx_sreg_envreg24",
+    "llvm.nvvm.read.ptx.sreg.envreg25" => "__nvvm_read_ptx_sreg_envreg25",
+    "llvm.nvvm.read.ptx.sreg.envreg26" => "__nvvm_read_ptx_sreg_envreg26",
+    "llvm.nvvm.read.ptx.sreg.envreg27" => "__nvvm_read_ptx_sreg_envreg27",
+    "llvm.nvvm.read.ptx.sreg.envreg28" => "__nvvm_read_ptx_sreg_envreg28",
+    "llvm.nvvm.read.ptx.sreg.envreg29" => "__nvvm_read_ptx_sreg_envreg29",
+    "llvm.nvvm.read.ptx.sreg.envreg3" => "__nvvm_read_ptx_sreg_envreg3",
+    "llvm.nvvm.read.ptx.sreg.envreg30" => "__nvvm_read_ptx_sreg_envreg30",
+    "llvm.nvvm.read.ptx.sreg.envreg31" => "__nvvm_read_ptx_sreg_envreg31",
+    "llvm.nvvm.read.ptx.sreg.envreg4" => "__nvvm_read_ptx_sreg_envreg4",
+    "llvm.nvvm.read.ptx.sreg.envreg5" => "__nvvm_read_ptx_sreg_envreg5",
+    "llvm.nvvm.read.ptx.sreg.envreg6" => "__nvvm_read_ptx_sreg_envreg6",
+    "llvm.nvvm.read.ptx.sreg.envreg7" => "__nvvm_read_ptx_sreg_envreg7",
+    "llvm.nvvm.read.ptx.sreg.envreg8" => "__nvvm_read_ptx_sreg_envreg8",
+    "llvm.nvvm.read.ptx.sreg.envreg9" => "__nvvm_read_ptx_sreg_envreg9",
+    "llvm.nvvm.read.ptx.sreg.gridid" => "__nvvm_read_ptx_sreg_",
+    "llvm.nvvm.read.ptx.sreg.laneid" => "__nvvm_read_ptx_sreg_",
+    "llvm.nvvm.read.ptx.sreg.lanemask.eq" => "__nvvm_read_ptx_sreg_",
+    "llvm.nvvm.read.ptx.sreg.lanemask.ge" => "__nvvm_read_ptx_sreg_",
+    "llvm.nvvm.read.ptx.sreg.lanemask.gt" => "__nvvm_read_ptx_sreg_",
+    "llvm.nvvm.read.ptx.sreg.lanemask.le" => "__nvvm_read_ptx_sreg_",
+    "llvm.nvvm.read.ptx.sreg.lanemask.lt" => "__nvvm_read_ptx_sreg_",
+    "llvm.nvvm.read.ptx.sreg.nctaid.x" => "__nvvm_read_ptx_sreg_nctaid_x",
+    "llvm.nvvm.read.ptx.sreg.nctaid.y" => "__nvvm_read_ptx_sreg_nctaid_y",
+    "llvm.nvvm.read.ptx.sreg.nctaid.z" => "__nvvm_read_ptx_sreg_nctaid_z",
+    "llvm.nvvm.read.ptx.sreg.nsmid" => "__nvvm_read_ptx_sreg_",
+    "llvm.nvvm.read.ptx.sreg.ntid.x" => "__nvvm_read_ptx_sreg_ntid_x",
+    "llvm.nvvm.read.ptx.sreg.ntid.y" => "__nvvm_read_ptx_sreg_ntid_y",
+    "llvm.nvvm.read.ptx.sreg.ntid.z" => "__nvvm_read_ptx_sreg_ntid_z",
+    "llvm.nvvm.read.ptx.sreg.nwarpid" => "__nvvm_read_ptx_sreg_",
+    "llvm.nvvm.read.ptx.sreg.pm0" => "__nvvm_read_ptx_sreg_",
+    "llvm.nvvm.read.ptx.sreg.pm1" => "__nvvm_read_ptx_sreg_",
+    "llvm.nvvm.read.ptx.sreg.pm2" => "__nvvm_read_ptx_sreg_",
+    "llvm.nvvm.read.ptx.sreg.pm3" => "__nvvm_read_ptx_sreg_",
+    "llvm.nvvm.read.ptx.sreg.smid" => "__nvvm_read_ptx_sreg_",
+    "llvm.nvvm.read.ptx.sreg.tid.x" => "__nvvm_read_ptx_sreg_tid_x",
+    "llvm.nvvm.read.ptx.sreg.tid.y" => "__nvvm_read_ptx_sreg_tid_y",
+    "llvm.nvvm.read.ptx.sreg.tid.z" => "__nvvm_read_ptx_sreg_tid_z",
+    "llvm.nvvm.read.ptx.sreg.warpid" => "__nvvm_read_ptx_sreg_",
+    "llvm.nvvm.read.ptx.sreg.warpsize" => "__nvvm_read_ptx_sreg_warpsize",
+    // [DUPLICATE]: "llvm.nvvm.read.ptx.sreg.warpsize" => "__nvvm_read_ptx_sreg_",
+    "llvm.nvvm.rotate.b32" => "__nvvm_rotate_b32",
+    "llvm.nvvm.rotate.b64" => "__nvvm_rotate_b64",
+    "llvm.nvvm.rotate.right.b64" => "__nvvm_rotate_right_b64",
+    "llvm.nvvm.round.d" => "__nvvm_round_d",
+    "llvm.nvvm.round.f" => "__nvvm_round_f",
+    "llvm.nvvm.round.ftz.f" => "__nvvm_round_ftz_f",
+    "llvm.nvvm.rsqrt.approx.d" => "__nvvm_rsqrt_approx_d",
+    "llvm.nvvm.rsqrt.approx.f" => "__nvvm_rsqrt_approx_f",
+    "llvm.nvvm.rsqrt.approx.ftz.f" => "__nvvm_rsqrt_approx_ftz_f",
+    "llvm.nvvm.sad.i" => "__nvvm_sad_i",
+    "llvm.nvvm.sad.ui" => "__nvvm_sad_ui",
+    "llvm.nvvm.saturate.d" => "__nvvm_saturate_d",
+    "llvm.nvvm.saturate.f" => "__nvvm_saturate_f",
+    "llvm.nvvm.saturate.ftz.f" => "__nvvm_saturate_ftz_f",
+    "llvm.nvvm.shfl.bfly.f32" => "__nvvm_shfl_bfly_f32",
+    "llvm.nvvm.shfl.bfly.i32" => "__nvvm_shfl_bfly_i32",
+    "llvm.nvvm.shfl.down.f32" => "__nvvm_shfl_down_f32",
+    "llvm.nvvm.shfl.down.i32" => "__nvvm_shfl_down_i32",
+    "llvm.nvvm.shfl.idx.f32" => "__nvvm_shfl_idx_f32",
+    "llvm.nvvm.shfl.idx.i32" => "__nvvm_shfl_idx_i32",
+    "llvm.nvvm.shfl.up.f32" => "__nvvm_shfl_up_f32",
+    "llvm.nvvm.shfl.up.i32" => "__nvvm_shfl_up_i32",
+    "llvm.nvvm.sin.approx.f" => "__nvvm_sin_approx_f",
+    "llvm.nvvm.sin.approx.ftz.f" => "__nvvm_sin_approx_ftz_f",
+    "llvm.nvvm.sqrt.approx.f" => "__nvvm_sqrt_approx_f",
+    "llvm.nvvm.sqrt.approx.ftz.f" => "__nvvm_sqrt_approx_ftz_f",
+    "llvm.nvvm.sqrt.f" => "__nvvm_sqrt_f",
+    "llvm.nvvm.sqrt.rm.d" => "__nvvm_sqrt_rm_d",
+    "llvm.nvvm.sqrt.rm.f" => "__nvvm_sqrt_rm_f",
+    "llvm.nvvm.sqrt.rm.ftz.f" => "__nvvm_sqrt_rm_ftz_f",
+    "llvm.nvvm.sqrt.rn.d" => "__nvvm_sqrt_rn_d",
+    "llvm.nvvm.sqrt.rn.f" => "__nvvm_sqrt_rn_f",
+    "llvm.nvvm.sqrt.rn.ftz.f" => "__nvvm_sqrt_rn_ftz_f",
+    "llvm.nvvm.sqrt.rp.d" => "__nvvm_sqrt_rp_d",
+    "llvm.nvvm.sqrt.rp.f" => "__nvvm_sqrt_rp_f",
+    "llvm.nvvm.sqrt.rp.ftz.f" => "__nvvm_sqrt_rp_ftz_f",
+    "llvm.nvvm.sqrt.rz.d" => "__nvvm_sqrt_rz_d",
+    "llvm.nvvm.sqrt.rz.f" => "__nvvm_sqrt_rz_f",
+    "llvm.nvvm.sqrt.rz.ftz.f" => "__nvvm_sqrt_rz_ftz_f",
+    "llvm.nvvm.suq.array.size" => "__nvvm_suq_array_size",
+    "llvm.nvvm.suq.channel.data.type" => "__nvvm_suq_channel_data_type",
+    "llvm.nvvm.suq.channel.order" => "__nvvm_suq_channel_order",
+    "llvm.nvvm.suq.depth" => "__nvvm_suq_depth",
+    "llvm.nvvm.suq.height" => "__nvvm_suq_height",
+    "llvm.nvvm.suq.width" => "__nvvm_suq_width",
+    "llvm.nvvm.sust.b.1d.array.i16.clamp" => "__nvvm_sust_b_1d_array_i16_clamp",
+    "llvm.nvvm.sust.b.1d.array.i16.trap" => "__nvvm_sust_b_1d_array_i16_trap",
+    "llvm.nvvm.sust.b.1d.array.i16.zero" => "__nvvm_sust_b_1d_array_i16_zero",
+    "llvm.nvvm.sust.b.1d.array.i32.clamp" => "__nvvm_sust_b_1d_array_i32_clamp",
+    "llvm.nvvm.sust.b.1d.array.i32.trap" => "__nvvm_sust_b_1d_array_i32_trap",
+    "llvm.nvvm.sust.b.1d.array.i32.zero" => "__nvvm_sust_b_1d_array_i32_zero",
+    "llvm.nvvm.sust.b.1d.array.i64.clamp" => "__nvvm_sust_b_1d_array_i64_clamp",
+    "llvm.nvvm.sust.b.1d.array.i64.trap" => "__nvvm_sust_b_1d_array_i64_trap",
+    "llvm.nvvm.sust.b.1d.array.i64.zero" => "__nvvm_sust_b_1d_array_i64_zero",
+    "llvm.nvvm.sust.b.1d.array.i8.clamp" => "__nvvm_sust_b_1d_array_i8_clamp",
+    "llvm.nvvm.sust.b.1d.array.i8.trap" => "__nvvm_sust_b_1d_array_i8_trap",
+    "llvm.nvvm.sust.b.1d.array.i8.zero" => "__nvvm_sust_b_1d_array_i8_zero",
+    "llvm.nvvm.sust.b.1d.array.v2i16.clamp" => "__nvvm_sust_b_1d_array_v2i16_clamp",
+    "llvm.nvvm.sust.b.1d.array.v2i16.trap" => "__nvvm_sust_b_1d_array_v2i16_trap",
+    "llvm.nvvm.sust.b.1d.array.v2i16.zero" => "__nvvm_sust_b_1d_array_v2i16_zero",
+    "llvm.nvvm.sust.b.1d.array.v2i32.clamp" => "__nvvm_sust_b_1d_array_v2i32_clamp",
+    "llvm.nvvm.sust.b.1d.array.v2i32.trap" => "__nvvm_sust_b_1d_array_v2i32_trap",
+    "llvm.nvvm.sust.b.1d.array.v2i32.zero" => "__nvvm_sust_b_1d_array_v2i32_zero",
+    "llvm.nvvm.sust.b.1d.array.v2i64.clamp" => "__nvvm_sust_b_1d_array_v2i64_clamp",
+    "llvm.nvvm.sust.b.1d.array.v2i64.trap" => "__nvvm_sust_b_1d_array_v2i64_trap",
+    "llvm.nvvm.sust.b.1d.array.v2i64.zero" => "__nvvm_sust_b_1d_array_v2i64_zero",
+    "llvm.nvvm.sust.b.1d.array.v2i8.clamp" => "__nvvm_sust_b_1d_array_v2i8_clamp",
+    "llvm.nvvm.sust.b.1d.array.v2i8.trap" => "__nvvm_sust_b_1d_array_v2i8_trap",
+    "llvm.nvvm.sust.b.1d.array.v2i8.zero" => "__nvvm_sust_b_1d_array_v2i8_zero",
+    "llvm.nvvm.sust.b.1d.array.v4i16.clamp" => "__nvvm_sust_b_1d_array_v4i16_clamp",
+    "llvm.nvvm.sust.b.1d.array.v4i16.trap" => "__nvvm_sust_b_1d_array_v4i16_trap",
+    "llvm.nvvm.sust.b.1d.array.v4i16.zero" => "__nvvm_sust_b_1d_array_v4i16_zero",
+    "llvm.nvvm.sust.b.1d.array.v4i32.clamp" => "__nvvm_sust_b_1d_array_v4i32_clamp",
+    "llvm.nvvm.sust.b.1d.array.v4i32.trap" => "__nvvm_sust_b_1d_array_v4i32_trap",
+    "llvm.nvvm.sust.b.1d.array.v4i32.zero" => "__nvvm_sust_b_1d_array_v4i32_zero",
+    "llvm.nvvm.sust.b.1d.array.v4i8.clamp" => "__nvvm_sust_b_1d_array_v4i8_clamp",
+    "llvm.nvvm.sust.b.1d.array.v4i8.trap" => "__nvvm_sust_b_1d_array_v4i8_trap",
+    "llvm.nvvm.sust.b.1d.array.v4i8.zero" => "__nvvm_sust_b_1d_array_v4i8_zero",
+    "llvm.nvvm.sust.b.1d.i16.clamp" => "__nvvm_sust_b_1d_i16_clamp",
+    "llvm.nvvm.sust.b.1d.i16.trap" => "__nvvm_sust_b_1d_i16_trap",
+    "llvm.nvvm.sust.b.1d.i16.zero" => "__nvvm_sust_b_1d_i16_zero",
+    "llvm.nvvm.sust.b.1d.i32.clamp" => "__nvvm_sust_b_1d_i32_clamp",
+    "llvm.nvvm.sust.b.1d.i32.trap" => "__nvvm_sust_b_1d_i32_trap",
+    "llvm.nvvm.sust.b.1d.i32.zero" => "__nvvm_sust_b_1d_i32_zero",
+    "llvm.nvvm.sust.b.1d.i64.clamp" => "__nvvm_sust_b_1d_i64_clamp",
+    "llvm.nvvm.sust.b.1d.i64.trap" => "__nvvm_sust_b_1d_i64_trap",
+    "llvm.nvvm.sust.b.1d.i64.zero" => "__nvvm_sust_b_1d_i64_zero",
+    "llvm.nvvm.sust.b.1d.i8.clamp" => "__nvvm_sust_b_1d_i8_clamp",
+    "llvm.nvvm.sust.b.1d.i8.trap" => "__nvvm_sust_b_1d_i8_trap",
+    "llvm.nvvm.sust.b.1d.i8.zero" => "__nvvm_sust_b_1d_i8_zero",
+    "llvm.nvvm.sust.b.1d.v2i16.clamp" => "__nvvm_sust_b_1d_v2i16_clamp",
+    "llvm.nvvm.sust.b.1d.v2i16.trap" => "__nvvm_sust_b_1d_v2i16_trap",
+    "llvm.nvvm.sust.b.1d.v2i16.zero" => "__nvvm_sust_b_1d_v2i16_zero",
+    "llvm.nvvm.sust.b.1d.v2i32.clamp" => "__nvvm_sust_b_1d_v2i32_clamp",
+    "llvm.nvvm.sust.b.1d.v2i32.trap" => "__nvvm_sust_b_1d_v2i32_trap",
+    "llvm.nvvm.sust.b.1d.v2i32.zero" => "__nvvm_sust_b_1d_v2i32_zero",
+    "llvm.nvvm.sust.b.1d.v2i64.clamp" => "__nvvm_sust_b_1d_v2i64_clamp",
+    "llvm.nvvm.sust.b.1d.v2i64.trap" => "__nvvm_sust_b_1d_v2i64_trap",
+    "llvm.nvvm.sust.b.1d.v2i64.zero" => "__nvvm_sust_b_1d_v2i64_zero",
+    "llvm.nvvm.sust.b.1d.v2i8.clamp" => "__nvvm_sust_b_1d_v2i8_clamp",
+    "llvm.nvvm.sust.b.1d.v2i8.trap" => "__nvvm_sust_b_1d_v2i8_trap",
+    "llvm.nvvm.sust.b.1d.v2i8.zero" => "__nvvm_sust_b_1d_v2i8_zero",
+    "llvm.nvvm.sust.b.1d.v4i16.clamp" => "__nvvm_sust_b_1d_v4i16_clamp",
+    "llvm.nvvm.sust.b.1d.v4i16.trap" => "__nvvm_sust_b_1d_v4i16_trap",
+    "llvm.nvvm.sust.b.1d.v4i16.zero" => "__nvvm_sust_b_1d_v4i16_zero",
+    "llvm.nvvm.sust.b.1d.v4i32.clamp" => "__nvvm_sust_b_1d_v4i32_clamp",
+    "llvm.nvvm.sust.b.1d.v4i32.trap" => "__nvvm_sust_b_1d_v4i32_trap",
+    "llvm.nvvm.sust.b.1d.v4i32.zero" => "__nvvm_sust_b_1d_v4i32_zero",
+    "llvm.nvvm.sust.b.1d.v4i8.clamp" => "__nvvm_sust_b_1d_v4i8_clamp",
+    "llvm.nvvm.sust.b.1d.v4i8.trap" => "__nvvm_sust_b_1d_v4i8_trap",
+    "llvm.nvvm.sust.b.1d.v4i8.zero" => "__nvvm_sust_b_1d_v4i8_zero",
+    "llvm.nvvm.sust.b.2d.array.i16.clamp" => "__nvvm_sust_b_2d_array_i16_clamp",
+    "llvm.nvvm.sust.b.2d.array.i16.trap" => "__nvvm_sust_b_2d_array_i16_trap",
+    "llvm.nvvm.sust.b.2d.array.i16.zero" => "__nvvm_sust_b_2d_array_i16_zero",
+    "llvm.nvvm.sust.b.2d.array.i32.clamp" => "__nvvm_sust_b_2d_array_i32_clamp",
+    "llvm.nvvm.sust.b.2d.array.i32.trap" => "__nvvm_sust_b_2d_array_i32_trap",
+    "llvm.nvvm.sust.b.2d.array.i32.zero" => "__nvvm_sust_b_2d_array_i32_zero",
+    "llvm.nvvm.sust.b.2d.array.i64.clamp" => "__nvvm_sust_b_2d_array_i64_clamp",
+    "llvm.nvvm.sust.b.2d.array.i64.trap" => "__nvvm_sust_b_2d_array_i64_trap",
+    "llvm.nvvm.sust.b.2d.array.i64.zero" => "__nvvm_sust_b_2d_array_i64_zero",
+    "llvm.nvvm.sust.b.2d.array.i8.clamp" => "__nvvm_sust_b_2d_array_i8_clamp",
+    "llvm.nvvm.sust.b.2d.array.i8.trap" => "__nvvm_sust_b_2d_array_i8_trap",
+    "llvm.nvvm.sust.b.2d.array.i8.zero" => "__nvvm_sust_b_2d_array_i8_zero",
+    "llvm.nvvm.sust.b.2d.array.v2i16.clamp" => "__nvvm_sust_b_2d_array_v2i16_clamp",
+    "llvm.nvvm.sust.b.2d.array.v2i16.trap" => "__nvvm_sust_b_2d_array_v2i16_trap",
+    "llvm.nvvm.sust.b.2d.array.v2i16.zero" => "__nvvm_sust_b_2d_array_v2i16_zero",
+    "llvm.nvvm.sust.b.2d.array.v2i32.clamp" => "__nvvm_sust_b_2d_array_v2i32_clamp",
+    "llvm.nvvm.sust.b.2d.array.v2i32.trap" => "__nvvm_sust_b_2d_array_v2i32_trap",
+    "llvm.nvvm.sust.b.2d.array.v2i32.zero" => "__nvvm_sust_b_2d_array_v2i32_zero",
+    "llvm.nvvm.sust.b.2d.array.v2i64.clamp" => "__nvvm_sust_b_2d_array_v2i64_clamp",
+    "llvm.nvvm.sust.b.2d.array.v2i64.trap" => "__nvvm_sust_b_2d_array_v2i64_trap",
+    "llvm.nvvm.sust.b.2d.array.v2i64.zero" => "__nvvm_sust_b_2d_array_v2i64_zero",
+    "llvm.nvvm.sust.b.2d.array.v2i8.clamp" => "__nvvm_sust_b_2d_array_v2i8_clamp",
+    "llvm.nvvm.sust.b.2d.array.v2i8.trap" => "__nvvm_sust_b_2d_array_v2i8_trap",
+    "llvm.nvvm.sust.b.2d.array.v2i8.zero" => "__nvvm_sust_b_2d_array_v2i8_zero",
+    "llvm.nvvm.sust.b.2d.array.v4i16.clamp" => "__nvvm_sust_b_2d_array_v4i16_clamp",
+    "llvm.nvvm.sust.b.2d.array.v4i16.trap" => "__nvvm_sust_b_2d_array_v4i16_trap",
+    "llvm.nvvm.sust.b.2d.array.v4i16.zero" => "__nvvm_sust_b_2d_array_v4i16_zero",
+    "llvm.nvvm.sust.b.2d.array.v4i32.clamp" => "__nvvm_sust_b_2d_array_v4i32_clamp",
+    "llvm.nvvm.sust.b.2d.array.v4i32.trap" => "__nvvm_sust_b_2d_array_v4i32_trap",
+    "llvm.nvvm.sust.b.2d.array.v4i32.zero" => "__nvvm_sust_b_2d_array_v4i32_zero",
+    "llvm.nvvm.sust.b.2d.array.v4i8.clamp" => "__nvvm_sust_b_2d_array_v4i8_clamp",
+    "llvm.nvvm.sust.b.2d.array.v4i8.trap" => "__nvvm_sust_b_2d_array_v4i8_trap",
+    "llvm.nvvm.sust.b.2d.array.v4i8.zero" => "__nvvm_sust_b_2d_array_v4i8_zero",
+    "llvm.nvvm.sust.b.2d.i16.clamp" => "__nvvm_sust_b_2d_i16_clamp",
+    "llvm.nvvm.sust.b.2d.i16.trap" => "__nvvm_sust_b_2d_i16_trap",
+    "llvm.nvvm.sust.b.2d.i16.zero" => "__nvvm_sust_b_2d_i16_zero",
+    "llvm.nvvm.sust.b.2d.i32.clamp" => "__nvvm_sust_b_2d_i32_clamp",
+    "llvm.nvvm.sust.b.2d.i32.trap" => "__nvvm_sust_b_2d_i32_trap",
+    "llvm.nvvm.sust.b.2d.i32.zero" => "__nvvm_sust_b_2d_i32_zero",
+    "llvm.nvvm.sust.b.2d.i64.clamp" => "__nvvm_sust_b_2d_i64_clamp",
+    "llvm.nvvm.sust.b.2d.i64.trap" => "__nvvm_sust_b_2d_i64_trap",
+    "llvm.nvvm.sust.b.2d.i64.zero" => "__nvvm_sust_b_2d_i64_zero",
+    "llvm.nvvm.sust.b.2d.i8.clamp" => "__nvvm_sust_b_2d_i8_clamp",
+    "llvm.nvvm.sust.b.2d.i8.trap" => "__nvvm_sust_b_2d_i8_trap",
+    "llvm.nvvm.sust.b.2d.i8.zero" => "__nvvm_sust_b_2d_i8_zero",
+    "llvm.nvvm.sust.b.2d.v2i16.clamp" => "__nvvm_sust_b_2d_v2i16_clamp",
+    "llvm.nvvm.sust.b.2d.v2i16.trap" => "__nvvm_sust_b_2d_v2i16_trap",
+    "llvm.nvvm.sust.b.2d.v2i16.zero" => "__nvvm_sust_b_2d_v2i16_zero",
+    "llvm.nvvm.sust.b.2d.v2i32.clamp" => "__nvvm_sust_b_2d_v2i32_clamp",
+    "llvm.nvvm.sust.b.2d.v2i32.trap" => "__nvvm_sust_b_2d_v2i32_trap",
+    "llvm.nvvm.sust.b.2d.v2i32.zero" => "__nvvm_sust_b_2d_v2i32_zero",
+    "llvm.nvvm.sust.b.2d.v2i64.clamp" => "__nvvm_sust_b_2d_v2i64_clamp",
+    "llvm.nvvm.sust.b.2d.v2i64.trap" => "__nvvm_sust_b_2d_v2i64_trap",
+    "llvm.nvvm.sust.b.2d.v2i64.zero" => "__nvvm_sust_b_2d_v2i64_zero",
+    "llvm.nvvm.sust.b.2d.v2i8.clamp" => "__nvvm_sust_b_2d_v2i8_clamp",
+    "llvm.nvvm.sust.b.2d.v2i8.trap" => "__nvvm_sust_b_2d_v2i8_trap",
+    "llvm.nvvm.sust.b.2d.v2i8.zero" => "__nvvm_sust_b_2d_v2i8_zero",
+    "llvm.nvvm.sust.b.2d.v4i16.clamp" => "__nvvm_sust_b_2d_v4i16_clamp",
+    "llvm.nvvm.sust.b.2d.v4i16.trap" => "__nvvm_sust_b_2d_v4i16_trap",
+    "llvm.nvvm.sust.b.2d.v4i16.zero" => "__nvvm_sust_b_2d_v4i16_zero",
+    "llvm.nvvm.sust.b.2d.v4i32.clamp" => "__nvvm_sust_b_2d_v4i32_clamp",
+    "llvm.nvvm.sust.b.2d.v4i32.trap" => "__nvvm_sust_b_2d_v4i32_trap",
+    "llvm.nvvm.sust.b.2d.v4i32.zero" => "__nvvm_sust_b_2d_v4i32_zero",
+    "llvm.nvvm.sust.b.2d.v4i8.clamp" => "__nvvm_sust_b_2d_v4i8_clamp",
+    "llvm.nvvm.sust.b.2d.v4i8.trap" => "__nvvm_sust_b_2d_v4i8_trap",
+    "llvm.nvvm.sust.b.2d.v4i8.zero" => "__nvvm_sust_b_2d_v4i8_zero",
+    "llvm.nvvm.sust.b.3d.i16.clamp" => "__nvvm_sust_b_3d_i16_clamp",
+    "llvm.nvvm.sust.b.3d.i16.trap" => "__nvvm_sust_b_3d_i16_trap",
+    "llvm.nvvm.sust.b.3d.i16.zero" => "__nvvm_sust_b_3d_i16_zero",
+    "llvm.nvvm.sust.b.3d.i32.clamp" => "__nvvm_sust_b_3d_i32_clamp",
+    "llvm.nvvm.sust.b.3d.i32.trap" => "__nvvm_sust_b_3d_i32_trap",
+    "llvm.nvvm.sust.b.3d.i32.zero" => "__nvvm_sust_b_3d_i32_zero",
+    "llvm.nvvm.sust.b.3d.i64.clamp" => "__nvvm_sust_b_3d_i64_clamp",
+    "llvm.nvvm.sust.b.3d.i64.trap" => "__nvvm_sust_b_3d_i64_trap",
+    "llvm.nvvm.sust.b.3d.i64.zero" => "__nvvm_sust_b_3d_i64_zero",
+    "llvm.nvvm.sust.b.3d.i8.clamp" => "__nvvm_sust_b_3d_i8_clamp",
+    "llvm.nvvm.sust.b.3d.i8.trap" => "__nvvm_sust_b_3d_i8_trap",
+    "llvm.nvvm.sust.b.3d.i8.zero" => "__nvvm_sust_b_3d_i8_zero",
+    "llvm.nvvm.sust.b.3d.v2i16.clamp" => "__nvvm_sust_b_3d_v2i16_clamp",
+    "llvm.nvvm.sust.b.3d.v2i16.trap" => "__nvvm_sust_b_3d_v2i16_trap",
+    "llvm.nvvm.sust.b.3d.v2i16.zero" => "__nvvm_sust_b_3d_v2i16_zero",
+    "llvm.nvvm.sust.b.3d.v2i32.clamp" => "__nvvm_sust_b_3d_v2i32_clamp",
+    "llvm.nvvm.sust.b.3d.v2i32.trap" => "__nvvm_sust_b_3d_v2i32_trap",
+    "llvm.nvvm.sust.b.3d.v2i32.zero" => "__nvvm_sust_b_3d_v2i32_zero",
+    "llvm.nvvm.sust.b.3d.v2i64.clamp" => "__nvvm_sust_b_3d_v2i64_clamp",
+    "llvm.nvvm.sust.b.3d.v2i64.trap" => "__nvvm_sust_b_3d_v2i64_trap",
+    "llvm.nvvm.sust.b.3d.v2i64.zero" => "__nvvm_sust_b_3d_v2i64_zero",
+    "llvm.nvvm.sust.b.3d.v2i8.clamp" => "__nvvm_sust_b_3d_v2i8_clamp",
+    "llvm.nvvm.sust.b.3d.v2i8.trap" => "__nvvm_sust_b_3d_v2i8_trap",
+    "llvm.nvvm.sust.b.3d.v2i8.zero" => "__nvvm_sust_b_3d_v2i8_zero",
+    "llvm.nvvm.sust.b.3d.v4i16.clamp" => "__nvvm_sust_b_3d_v4i16_clamp",
+    "llvm.nvvm.sust.b.3d.v4i16.trap" => "__nvvm_sust_b_3d_v4i16_trap",
+    "llvm.nvvm.sust.b.3d.v4i16.zero" => "__nvvm_sust_b_3d_v4i16_zero",
+    "llvm.nvvm.sust.b.3d.v4i32.clamp" => "__nvvm_sust_b_3d_v4i32_clamp",
+    "llvm.nvvm.sust.b.3d.v4i32.trap" => "__nvvm_sust_b_3d_v4i32_trap",
+    "llvm.nvvm.sust.b.3d.v4i32.zero" => "__nvvm_sust_b_3d_v4i32_zero",
+    "llvm.nvvm.sust.b.3d.v4i8.clamp" => "__nvvm_sust_b_3d_v4i8_clamp",
+    "llvm.nvvm.sust.b.3d.v4i8.trap" => "__nvvm_sust_b_3d_v4i8_trap",
+    "llvm.nvvm.sust.b.3d.v4i8.zero" => "__nvvm_sust_b_3d_v4i8_zero",
+    "llvm.nvvm.sust.p.1d.array.i16.trap" => "__nvvm_sust_p_1d_array_i16_trap",
+    "llvm.nvvm.sust.p.1d.array.i32.trap" => "__nvvm_sust_p_1d_array_i32_trap",
+    "llvm.nvvm.sust.p.1d.array.i8.trap" => "__nvvm_sust_p_1d_array_i8_trap",
+    "llvm.nvvm.sust.p.1d.array.v2i16.trap" => "__nvvm_sust_p_1d_array_v2i16_trap",
+    "llvm.nvvm.sust.p.1d.array.v2i32.trap" => "__nvvm_sust_p_1d_array_v2i32_trap",
+    "llvm.nvvm.sust.p.1d.array.v2i8.trap" => "__nvvm_sust_p_1d_array_v2i8_trap",
+    "llvm.nvvm.sust.p.1d.array.v4i16.trap" => "__nvvm_sust_p_1d_array_v4i16_trap",
+    "llvm.nvvm.sust.p.1d.array.v4i32.trap" => "__nvvm_sust_p_1d_array_v4i32_trap",
+    "llvm.nvvm.sust.p.1d.array.v4i8.trap" => "__nvvm_sust_p_1d_array_v4i8_trap",
+    "llvm.nvvm.sust.p.1d.i16.trap" => "__nvvm_sust_p_1d_i16_trap",
+    "llvm.nvvm.sust.p.1d.i32.trap" => "__nvvm_sust_p_1d_i32_trap",
+    "llvm.nvvm.sust.p.1d.i8.trap" => "__nvvm_sust_p_1d_i8_trap",
+    "llvm.nvvm.sust.p.1d.v2i16.trap" => "__nvvm_sust_p_1d_v2i16_trap",
+    "llvm.nvvm.sust.p.1d.v2i32.trap" => "__nvvm_sust_p_1d_v2i32_trap",
+    "llvm.nvvm.sust.p.1d.v2i8.trap" => "__nvvm_sust_p_1d_v2i8_trap",
+    "llvm.nvvm.sust.p.1d.v4i16.trap" => "__nvvm_sust_p_1d_v4i16_trap",
+    "llvm.nvvm.sust.p.1d.v4i32.trap" => "__nvvm_sust_p_1d_v4i32_trap",
+    "llvm.nvvm.sust.p.1d.v4i8.trap" => "__nvvm_sust_p_1d_v4i8_trap",
+    "llvm.nvvm.sust.p.2d.array.i16.trap" => "__nvvm_sust_p_2d_array_i16_trap",
+    "llvm.nvvm.sust.p.2d.array.i32.trap" => "__nvvm_sust_p_2d_array_i32_trap",
+    "llvm.nvvm.sust.p.2d.array.i8.trap" => "__nvvm_sust_p_2d_array_i8_trap",
+    "llvm.nvvm.sust.p.2d.array.v2i16.trap" => "__nvvm_sust_p_2d_array_v2i16_trap",
+    "llvm.nvvm.sust.p.2d.array.v2i32.trap" => "__nvvm_sust_p_2d_array_v2i32_trap",
+    "llvm.nvvm.sust.p.2d.array.v2i8.trap" => "__nvvm_sust_p_2d_array_v2i8_trap",
+    "llvm.nvvm.sust.p.2d.array.v4i16.trap" => "__nvvm_sust_p_2d_array_v4i16_trap",
+    "llvm.nvvm.sust.p.2d.array.v4i32.trap" => "__nvvm_sust_p_2d_array_v4i32_trap",
+    "llvm.nvvm.sust.p.2d.array.v4i8.trap" => "__nvvm_sust_p_2d_array_v4i8_trap",
+    "llvm.nvvm.sust.p.2d.i16.trap" => "__nvvm_sust_p_2d_i16_trap",
+    "llvm.nvvm.sust.p.2d.i32.trap" => "__nvvm_sust_p_2d_i32_trap",
+    "llvm.nvvm.sust.p.2d.i8.trap" => "__nvvm_sust_p_2d_i8_trap",
+    "llvm.nvvm.sust.p.2d.v2i16.trap" => "__nvvm_sust_p_2d_v2i16_trap",
+    "llvm.nvvm.sust.p.2d.v2i32.trap" => "__nvvm_sust_p_2d_v2i32_trap",
+    "llvm.nvvm.sust.p.2d.v2i8.trap" => "__nvvm_sust_p_2d_v2i8_trap",
+    "llvm.nvvm.sust.p.2d.v4i16.trap" => "__nvvm_sust_p_2d_v4i16_trap",
+    "llvm.nvvm.sust.p.2d.v4i32.trap" => "__nvvm_sust_p_2d_v4i32_trap",
+    "llvm.nvvm.sust.p.2d.v4i8.trap" => "__nvvm_sust_p_2d_v4i8_trap",
+    "llvm.nvvm.sust.p.3d.i16.trap" => "__nvvm_sust_p_3d_i16_trap",
+    "llvm.nvvm.sust.p.3d.i32.trap" => "__nvvm_sust_p_3d_i32_trap",
+    "llvm.nvvm.sust.p.3d.i8.trap" => "__nvvm_sust_p_3d_i8_trap",
+    "llvm.nvvm.sust.p.3d.v2i16.trap" => "__nvvm_sust_p_3d_v2i16_trap",
+    "llvm.nvvm.sust.p.3d.v2i32.trap" => "__nvvm_sust_p_3d_v2i32_trap",
+    "llvm.nvvm.sust.p.3d.v2i8.trap" => "__nvvm_sust_p_3d_v2i8_trap",
+    "llvm.nvvm.sust.p.3d.v4i16.trap" => "__nvvm_sust_p_3d_v4i16_trap",
+    "llvm.nvvm.sust.p.3d.v4i32.trap" => "__nvvm_sust_p_3d_v4i32_trap",
+    "llvm.nvvm.sust.p.3d.v4i8.trap" => "__nvvm_sust_p_3d_v4i8_trap",
+    "llvm.nvvm.swap.lo.hi.b64" => "__nvvm_swap_lo_hi_b64",
+    "llvm.nvvm.trunc.d" => "__nvvm_trunc_d",
+    "llvm.nvvm.trunc.f" => "__nvvm_trunc_f",
+    "llvm.nvvm.trunc.ftz.f" => "__nvvm_trunc_ftz_f",
+    "llvm.nvvm.txq.array.size" => "__nvvm_txq_array_size",
+    "llvm.nvvm.txq.channel.data.type" => "__nvvm_txq_channel_data_type",
+    "llvm.nvvm.txq.channel.order" => "__nvvm_txq_channel_order",
+    "llvm.nvvm.txq.depth" => "__nvvm_txq_depth",
+    "llvm.nvvm.txq.height" => "__nvvm_txq_height",
+    "llvm.nvvm.txq.num.mipmap.levels" => "__nvvm_txq_num_mipmap_levels",
+    "llvm.nvvm.txq.num.samples" => "__nvvm_txq_num_samples",
+    "llvm.nvvm.txq.width" => "__nvvm_txq_width",
+    "llvm.nvvm.ui2d.rm" => "__nvvm_ui2d_rm",
+    "llvm.nvvm.ui2d.rn" => "__nvvm_ui2d_rn",
+    "llvm.nvvm.ui2d.rp" => "__nvvm_ui2d_rp",
+    "llvm.nvvm.ui2d.rz" => "__nvvm_ui2d_rz",
+    "llvm.nvvm.ui2f.rm" => "__nvvm_ui2f_rm",
+    "llvm.nvvm.ui2f.rn" => "__nvvm_ui2f_rn",
+    "llvm.nvvm.ui2f.rp" => "__nvvm_ui2f_rp",
+    "llvm.nvvm.ui2f.rz" => "__nvvm_ui2f_rz",
+    "llvm.nvvm.ull2d.rm" => "__nvvm_ull2d_rm",
+    "llvm.nvvm.ull2d.rn" => "__nvvm_ull2d_rn",
+    "llvm.nvvm.ull2d.rp" => "__nvvm_ull2d_rp",
+    "llvm.nvvm.ull2d.rz" => "__nvvm_ull2d_rz",
+    "llvm.nvvm.ull2f.rm" => "__nvvm_ull2f_rm",
+    "llvm.nvvm.ull2f.rn" => "__nvvm_ull2f_rn",
+    "llvm.nvvm.ull2f.rp" => "__nvvm_ull2f_rp",
+    "llvm.nvvm.ull2f.rz" => "__nvvm_ull2f_rz",
+    // ppc
+    "llvm.ppc.addex" => "__builtin_ppc_addex",
+    "llvm.ppc.addf128.round.to.odd" => "__builtin_addf128_round_to_odd",
+    "llvm.ppc.altivec.crypto.vcipher" => "__builtin_altivec_crypto_vcipher",
+    "llvm.ppc.altivec.crypto.vcipherlast" => "__builtin_altivec_crypto_vcipherlast",
+    "llvm.ppc.altivec.crypto.vncipher" => "__builtin_altivec_crypto_vncipher",
+    "llvm.ppc.altivec.crypto.vncipherlast" => "__builtin_altivec_crypto_vncipherlast",
+    "llvm.ppc.altivec.crypto.vpermxor" => "__builtin_altivec_crypto_vpermxor",
+    "llvm.ppc.altivec.crypto.vpermxor.be" => "__builtin_altivec_crypto_vpermxor_be",
+    "llvm.ppc.altivec.crypto.vpmsumb" => "__builtin_altivec_crypto_vpmsumb",
+    "llvm.ppc.altivec.crypto.vpmsumd" => "__builtin_altivec_crypto_vpmsumd",
+    "llvm.ppc.altivec.crypto.vpmsumh" => "__builtin_altivec_crypto_vpmsumh",
+    "llvm.ppc.altivec.crypto.vpmsumw" => "__builtin_altivec_crypto_vpmsumw",
+    "llvm.ppc.altivec.crypto.vsbox" => "__builtin_altivec_crypto_vsbox",
+    "llvm.ppc.altivec.crypto.vshasigmad" => "__builtin_altivec_crypto_vshasigmad",
+    "llvm.ppc.altivec.crypto.vshasigmaw" => "__builtin_altivec_crypto_vshasigmaw",
+    "llvm.ppc.altivec.dss" => "__builtin_altivec_dss",
+    "llvm.ppc.altivec.dssall" => "__builtin_altivec_dssall",
+    "llvm.ppc.altivec.dst" => "__builtin_altivec_dst",
+    "llvm.ppc.altivec.dstst" => "__builtin_altivec_dstst",
+    "llvm.ppc.altivec.dststt" => "__builtin_altivec_dststt",
+    "llvm.ppc.altivec.dstt" => "__builtin_altivec_dstt",
+    "llvm.ppc.altivec.mfvscr" => "__builtin_altivec_mfvscr",
+    "llvm.ppc.altivec.mtvscr" => "__builtin_altivec_mtvscr",
+    "llvm.ppc.altivec.mtvsrbm" => "__builtin_altivec_mtvsrbm",
+    "llvm.ppc.altivec.mtvsrdm" => "__builtin_altivec_mtvsrdm",
+    "llvm.ppc.altivec.mtvsrhm" => "__builtin_altivec_mtvsrhm",
+    "llvm.ppc.altivec.mtvsrqm" => "__builtin_altivec_mtvsrqm",
+    "llvm.ppc.altivec.mtvsrwm" => "__builtin_altivec_mtvsrwm",
+    "llvm.ppc.altivec.vaddcuw" => "__builtin_altivec_vaddcuw",
+    "llvm.ppc.altivec.vaddecuq" => "__builtin_altivec_vaddecuq",
+    "llvm.ppc.altivec.vaddeuqm" => "__builtin_altivec_vaddeuqm",
+    "llvm.ppc.altivec.vaddsbs" => "__builtin_altivec_vaddsbs",
+    "llvm.ppc.altivec.vaddshs" => "__builtin_altivec_vaddshs",
+    "llvm.ppc.altivec.vaddsws" => "__builtin_altivec_vaddsws",
+    "llvm.ppc.altivec.vaddubs" => "__builtin_altivec_vaddubs",
+    "llvm.ppc.altivec.vadduhs" => "__builtin_altivec_vadduhs",
+    "llvm.ppc.altivec.vadduws" => "__builtin_altivec_vadduws",
+    "llvm.ppc.altivec.vavgsb" => "__builtin_altivec_vavgsb",
+    "llvm.ppc.altivec.vavgsh" => "__builtin_altivec_vavgsh",
+    "llvm.ppc.altivec.vavgsw" => "__builtin_altivec_vavgsw",
+    "llvm.ppc.altivec.vavgub" => "__builtin_altivec_vavgub",
+    "llvm.ppc.altivec.vavguh" => "__builtin_altivec_vavguh",
+    "llvm.ppc.altivec.vavguw" => "__builtin_altivec_vavguw",
+    "llvm.ppc.altivec.vbpermd" => "__builtin_altivec_vbpermd",
+    "llvm.ppc.altivec.vbpermq" => "__builtin_altivec_vbpermq",
+    "llvm.ppc.altivec.vcfsx" => "__builtin_altivec_vcfsx",
+    "llvm.ppc.altivec.vcfuged" => "__builtin_altivec_vcfuged",
+    "llvm.ppc.altivec.vcfux" => "__builtin_altivec_vcfux",
+    "llvm.ppc.altivec.vclrlb" => "__builtin_altivec_vclrlb",
+    "llvm.ppc.altivec.vclrrb" => "__builtin_altivec_vclrrb",
+    "llvm.ppc.altivec.vclzdm" => "__builtin_altivec_vclzdm",
+    "llvm.ppc.altivec.vclzlsbb" => "__builtin_altivec_vclzlsbb",
+    "llvm.ppc.altivec.vcmpbfp" => "__builtin_altivec_vcmpbfp",
+    "llvm.ppc.altivec.vcmpbfp.p" => "__builtin_altivec_vcmpbfp_p",
+    "llvm.ppc.altivec.vcmpeqfp" => "__builtin_altivec_vcmpeqfp",
+    "llvm.ppc.altivec.vcmpeqfp.p" => "__builtin_altivec_vcmpeqfp_p",
+    "llvm.ppc.altivec.vcmpequb" => "__builtin_altivec_vcmpequb",
+    "llvm.ppc.altivec.vcmpequb.p" => "__builtin_altivec_vcmpequb_p",
+    "llvm.ppc.altivec.vcmpequd" => "__builtin_altivec_vcmpequd",
+    "llvm.ppc.altivec.vcmpequd.p" => "__builtin_altivec_vcmpequd_p",
+    "llvm.ppc.altivec.vcmpequh" => "__builtin_altivec_vcmpequh",
+    "llvm.ppc.altivec.vcmpequh.p" => "__builtin_altivec_vcmpequh_p",
+    "llvm.ppc.altivec.vcmpequq" => "__builtin_altivec_vcmpequq",
+    "llvm.ppc.altivec.vcmpequq.p" => "__builtin_altivec_vcmpequq_p",
+    "llvm.ppc.altivec.vcmpequw" => "__builtin_altivec_vcmpequw",
+    "llvm.ppc.altivec.vcmpequw.p" => "__builtin_altivec_vcmpequw_p",
+    "llvm.ppc.altivec.vcmpgefp" => "__builtin_altivec_vcmpgefp",
+    "llvm.ppc.altivec.vcmpgefp.p" => "__builtin_altivec_vcmpgefp_p",
+    "llvm.ppc.altivec.vcmpgtfp" => "__builtin_altivec_vcmpgtfp",
+    "llvm.ppc.altivec.vcmpgtfp.p" => "__builtin_altivec_vcmpgtfp_p",
+    "llvm.ppc.altivec.vcmpgtsb" => "__builtin_altivec_vcmpgtsb",
+    "llvm.ppc.altivec.vcmpgtsb.p" => "__builtin_altivec_vcmpgtsb_p",
+    "llvm.ppc.altivec.vcmpgtsd" => "__builtin_altivec_vcmpgtsd",
+    "llvm.ppc.altivec.vcmpgtsd.p" => "__builtin_altivec_vcmpgtsd_p",
+    "llvm.ppc.altivec.vcmpgtsh" => "__builtin_altivec_vcmpgtsh",
+    "llvm.ppc.altivec.vcmpgtsh.p" => "__builtin_altivec_vcmpgtsh_p",
+    "llvm.ppc.altivec.vcmpgtsq" => "__builtin_altivec_vcmpgtsq",
+    "llvm.ppc.altivec.vcmpgtsq.p" => "__builtin_altivec_vcmpgtsq_p",
+    "llvm.ppc.altivec.vcmpgtsw" => "__builtin_altivec_vcmpgtsw",
+    "llvm.ppc.altivec.vcmpgtsw.p" => "__builtin_altivec_vcmpgtsw_p",
+    "llvm.ppc.altivec.vcmpgtub" => "__builtin_altivec_vcmpgtub",
+    "llvm.ppc.altivec.vcmpgtub.p" => "__builtin_altivec_vcmpgtub_p",
+    "llvm.ppc.altivec.vcmpgtud" => "__builtin_altivec_vcmpgtud",
+    "llvm.ppc.altivec.vcmpgtud.p" => "__builtin_altivec_vcmpgtud_p",
+    "llvm.ppc.altivec.vcmpgtuh" => "__builtin_altivec_vcmpgtuh",
+    "llvm.ppc.altivec.vcmpgtuh.p" => "__builtin_altivec_vcmpgtuh_p",
+    "llvm.ppc.altivec.vcmpgtuq" => "__builtin_altivec_vcmpgtuq",
+    "llvm.ppc.altivec.vcmpgtuq.p" => "__builtin_altivec_vcmpgtuq_p",
+    "llvm.ppc.altivec.vcmpgtuw" => "__builtin_altivec_vcmpgtuw",
+    "llvm.ppc.altivec.vcmpgtuw.p" => "__builtin_altivec_vcmpgtuw_p",
+    "llvm.ppc.altivec.vcmpneb" => "__builtin_altivec_vcmpneb",
+    "llvm.ppc.altivec.vcmpneb.p" => "__builtin_altivec_vcmpneb_p",
+    "llvm.ppc.altivec.vcmpneh" => "__builtin_altivec_vcmpneh",
+    "llvm.ppc.altivec.vcmpneh.p" => "__builtin_altivec_vcmpneh_p",
+    "llvm.ppc.altivec.vcmpnew" => "__builtin_altivec_vcmpnew",
+    "llvm.ppc.altivec.vcmpnew.p" => "__builtin_altivec_vcmpnew_p",
+    "llvm.ppc.altivec.vcmpnezb" => "__builtin_altivec_vcmpnezb",
+    "llvm.ppc.altivec.vcmpnezb.p" => "__builtin_altivec_vcmpnezb_p",
+    "llvm.ppc.altivec.vcmpnezh" => "__builtin_altivec_vcmpnezh",
+    "llvm.ppc.altivec.vcmpnezh.p" => "__builtin_altivec_vcmpnezh_p",
+    "llvm.ppc.altivec.vcmpnezw" => "__builtin_altivec_vcmpnezw",
+    "llvm.ppc.altivec.vcmpnezw.p" => "__builtin_altivec_vcmpnezw_p",
+    "llvm.ppc.altivec.vcntmbb" => "__builtin_altivec_vcntmbb",
+    "llvm.ppc.altivec.vcntmbd" => "__builtin_altivec_vcntmbd",
+    "llvm.ppc.altivec.vcntmbh" => "__builtin_altivec_vcntmbh",
+    "llvm.ppc.altivec.vcntmbw" => "__builtin_altivec_vcntmbw",
+    "llvm.ppc.altivec.vctsxs" => "__builtin_altivec_vctsxs",
+    "llvm.ppc.altivec.vctuxs" => "__builtin_altivec_vctuxs",
+    "llvm.ppc.altivec.vctzdm" => "__builtin_altivec_vctzdm",
+    "llvm.ppc.altivec.vctzlsbb" => "__builtin_altivec_vctzlsbb",
+    "llvm.ppc.altivec.vexpandbm" => "__builtin_altivec_vexpandbm",
+    "llvm.ppc.altivec.vexpanddm" => "__builtin_altivec_vexpanddm",
+    "llvm.ppc.altivec.vexpandhm" => "__builtin_altivec_vexpandhm",
+    "llvm.ppc.altivec.vexpandqm" => "__builtin_altivec_vexpandqm",
+    "llvm.ppc.altivec.vexpandwm" => "__builtin_altivec_vexpandwm",
+    "llvm.ppc.altivec.vexptefp" => "__builtin_altivec_vexptefp",
+    "llvm.ppc.altivec.vextddvlx" => "__builtin_altivec_vextddvlx",
+    "llvm.ppc.altivec.vextddvrx" => "__builtin_altivec_vextddvrx",
+    "llvm.ppc.altivec.vextdubvlx" => "__builtin_altivec_vextdubvlx",
+    "llvm.ppc.altivec.vextdubvrx" => "__builtin_altivec_vextdubvrx",
+    "llvm.ppc.altivec.vextduhvlx" => "__builtin_altivec_vextduhvlx",
+    "llvm.ppc.altivec.vextduhvrx" => "__builtin_altivec_vextduhvrx",
+    "llvm.ppc.altivec.vextduwvlx" => "__builtin_altivec_vextduwvlx",
+    "llvm.ppc.altivec.vextduwvrx" => "__builtin_altivec_vextduwvrx",
+    "llvm.ppc.altivec.vextractbm" => "__builtin_altivec_vextractbm",
+    "llvm.ppc.altivec.vextractdm" => "__builtin_altivec_vextractdm",
+    "llvm.ppc.altivec.vextracthm" => "__builtin_altivec_vextracthm",
+    "llvm.ppc.altivec.vextractqm" => "__builtin_altivec_vextractqm",
+    "llvm.ppc.altivec.vextractwm" => "__builtin_altivec_vextractwm",
+    "llvm.ppc.altivec.vextsb2d" => "__builtin_altivec_vextsb2d",
+    "llvm.ppc.altivec.vextsb2w" => "__builtin_altivec_vextsb2w",
+    "llvm.ppc.altivec.vextsd2q" => "__builtin_altivec_vextsd2q",
+    "llvm.ppc.altivec.vextsh2d" => "__builtin_altivec_vextsh2d",
+    "llvm.ppc.altivec.vextsh2w" => "__builtin_altivec_vextsh2w",
+    "llvm.ppc.altivec.vextsw2d" => "__builtin_altivec_vextsw2d",
+    "llvm.ppc.altivec.vgbbd" => "__builtin_altivec_vgbbd",
+    "llvm.ppc.altivec.vgnb" => "__builtin_altivec_vgnb",
+    "llvm.ppc.altivec.vinsblx" => "__builtin_altivec_vinsblx",
+    "llvm.ppc.altivec.vinsbrx" => "__builtin_altivec_vinsbrx",
+    "llvm.ppc.altivec.vinsbvlx" => "__builtin_altivec_vinsbvlx",
+    "llvm.ppc.altivec.vinsbvrx" => "__builtin_altivec_vinsbvrx",
+    "llvm.ppc.altivec.vinsdlx" => "__builtin_altivec_vinsdlx",
+    "llvm.ppc.altivec.vinsdrx" => "__builtin_altivec_vinsdrx",
+    "llvm.ppc.altivec.vinshlx" => "__builtin_altivec_vinshlx",
+    "llvm.ppc.altivec.vinshrx" => "__builtin_altivec_vinshrx",
+    "llvm.ppc.altivec.vinshvlx" => "__builtin_altivec_vinshvlx",
+    "llvm.ppc.altivec.vinshvrx" => "__builtin_altivec_vinshvrx",
+    "llvm.ppc.altivec.vinswlx" => "__builtin_altivec_vinswlx",
+    "llvm.ppc.altivec.vinswrx" => "__builtin_altivec_vinswrx",
+    "llvm.ppc.altivec.vinswvlx" => "__builtin_altivec_vinswvlx",
+    "llvm.ppc.altivec.vinswvrx" => "__builtin_altivec_vinswvrx",
+    "llvm.ppc.altivec.vlogefp" => "__builtin_altivec_vlogefp",
+    "llvm.ppc.altivec.vmaddfp" => "__builtin_altivec_vmaddfp",
+    "llvm.ppc.altivec.vmaxfp" => "__builtin_altivec_vmaxfp",
+    "llvm.ppc.altivec.vmaxsb" => "__builtin_altivec_vmaxsb",
+    "llvm.ppc.altivec.vmaxsd" => "__builtin_altivec_vmaxsd",
+    "llvm.ppc.altivec.vmaxsh" => "__builtin_altivec_vmaxsh",
+    "llvm.ppc.altivec.vmaxsw" => "__builtin_altivec_vmaxsw",
+    "llvm.ppc.altivec.vmaxub" => "__builtin_altivec_vmaxub",
+    "llvm.ppc.altivec.vmaxud" => "__builtin_altivec_vmaxud",
+    "llvm.ppc.altivec.vmaxuh" => "__builtin_altivec_vmaxuh",
+    "llvm.ppc.altivec.vmaxuw" => "__builtin_altivec_vmaxuw",
+    "llvm.ppc.altivec.vmhaddshs" => "__builtin_altivec_vmhaddshs",
+    "llvm.ppc.altivec.vmhraddshs" => "__builtin_altivec_vmhraddshs",
+    "llvm.ppc.altivec.vminfp" => "__builtin_altivec_vminfp",
+    "llvm.ppc.altivec.vminsb" => "__builtin_altivec_vminsb",
+    "llvm.ppc.altivec.vminsd" => "__builtin_altivec_vminsd",
+    "llvm.ppc.altivec.vminsh" => "__builtin_altivec_vminsh",
+    "llvm.ppc.altivec.vminsw" => "__builtin_altivec_vminsw",
+    "llvm.ppc.altivec.vminub" => "__builtin_altivec_vminub",
+    "llvm.ppc.altivec.vminud" => "__builtin_altivec_vminud",
+    "llvm.ppc.altivec.vminuh" => "__builtin_altivec_vminuh",
+    "llvm.ppc.altivec.vminuw" => "__builtin_altivec_vminuw",
+    "llvm.ppc.altivec.vmladduhm" => "__builtin_altivec_vmladduhm",
+    "llvm.ppc.altivec.vmsumcud" => "__builtin_altivec_vmsumcud",
+    "llvm.ppc.altivec.vmsummbm" => "__builtin_altivec_vmsummbm",
+    "llvm.ppc.altivec.vmsumshm" => "__builtin_altivec_vmsumshm",
+    "llvm.ppc.altivec.vmsumshs" => "__builtin_altivec_vmsumshs",
+    "llvm.ppc.altivec.vmsumubm" => "__builtin_altivec_vmsumubm",
+    "llvm.ppc.altivec.vmsumudm" => "__builtin_altivec_vmsumudm",
+    "llvm.ppc.altivec.vmsumuhm" => "__builtin_altivec_vmsumuhm",
+    "llvm.ppc.altivec.vmsumuhs" => "__builtin_altivec_vmsumuhs",
+    "llvm.ppc.altivec.vmulesb" => "__builtin_altivec_vmulesb",
+    "llvm.ppc.altivec.vmulesh" => "__builtin_altivec_vmulesh",
+    "llvm.ppc.altivec.vmulesw" => "__builtin_altivec_vmulesw",
+    "llvm.ppc.altivec.vmuleub" => "__builtin_altivec_vmuleub",
+    "llvm.ppc.altivec.vmuleuh" => "__builtin_altivec_vmuleuh",
+    "llvm.ppc.altivec.vmuleuw" => "__builtin_altivec_vmuleuw",
+    "llvm.ppc.altivec.vmulosb" => "__builtin_altivec_vmulosb",
+    "llvm.ppc.altivec.vmulosh" => "__builtin_altivec_vmulosh",
+    "llvm.ppc.altivec.vmulosw" => "__builtin_altivec_vmulosw",
+    "llvm.ppc.altivec.vmuloub" => "__builtin_altivec_vmuloub",
+    "llvm.ppc.altivec.vmulouh" => "__builtin_altivec_vmulouh",
+    "llvm.ppc.altivec.vmulouw" => "__builtin_altivec_vmulouw",
+    "llvm.ppc.altivec.vnmsubfp" => "__builtin_altivec_vnmsubfp",
+    "llvm.ppc.altivec.vpdepd" => "__builtin_altivec_vpdepd",
+    "llvm.ppc.altivec.vperm" => "__builtin_altivec_vperm_4si",
+    "llvm.ppc.altivec.vpextd" => "__builtin_altivec_vpextd",
+    "llvm.ppc.altivec.vpkpx" => "__builtin_altivec_vpkpx",
+    "llvm.ppc.altivec.vpksdss" => "__builtin_altivec_vpksdss",
+    "llvm.ppc.altivec.vpksdus" => "__builtin_altivec_vpksdus",
+    "llvm.ppc.altivec.vpkshss" => "__builtin_altivec_vpkshss",
+    "llvm.ppc.altivec.vpkshus" => "__builtin_altivec_vpkshus",
+    "llvm.ppc.altivec.vpkswss" => "__builtin_altivec_vpkswss",
+    "llvm.ppc.altivec.vpkswus" => "__builtin_altivec_vpkswus",
+    "llvm.ppc.altivec.vpkudus" => "__builtin_altivec_vpkudus",
+    "llvm.ppc.altivec.vpkuhus" => "__builtin_altivec_vpkuhus",
+    "llvm.ppc.altivec.vpkuwus" => "__builtin_altivec_vpkuwus",
+    "llvm.ppc.altivec.vprtybd" => "__builtin_altivec_vprtybd",
+    "llvm.ppc.altivec.vprtybq" => "__builtin_altivec_vprtybq",
+    "llvm.ppc.altivec.vprtybw" => "__builtin_altivec_vprtybw",
+    "llvm.ppc.altivec.vrefp" => "__builtin_altivec_vrefp",
+    "llvm.ppc.altivec.vrfim" => "__builtin_altivec_vrfim",
+    "llvm.ppc.altivec.vrfin" => "__builtin_altivec_vrfin",
+    "llvm.ppc.altivec.vrfip" => "__builtin_altivec_vrfip",
+    "llvm.ppc.altivec.vrfiz" => "__builtin_altivec_vrfiz",
+    "llvm.ppc.altivec.vrlb" => "__builtin_altivec_vrlb",
+    "llvm.ppc.altivec.vrld" => "__builtin_altivec_vrld",
+    "llvm.ppc.altivec.vrlh" => "__builtin_altivec_vrlh",
+    "llvm.ppc.altivec.vrlw" => "__builtin_altivec_vrlw",
+    "llvm.ppc.altivec.vrsqrtefp" => "__builtin_altivec_vrsqrtefp",
+    "llvm.ppc.altivec.vsel" => "__builtin_altivec_vsel_4si",
+    "llvm.ppc.altivec.vsl" => "__builtin_altivec_vsl",
+    "llvm.ppc.altivec.vslb" => "__builtin_altivec_vslb",
+    "llvm.ppc.altivec.vsldbi" => "__builtin_altivec_vsldbi",
+    "llvm.ppc.altivec.vslh" => "__builtin_altivec_vslh",
+    "llvm.ppc.altivec.vslo" => "__builtin_altivec_vslo",
+    "llvm.ppc.altivec.vslw" => "__builtin_altivec_vslw",
+    "llvm.ppc.altivec.vsr" => "__builtin_altivec_vsr",
+    "llvm.ppc.altivec.vsrab" => "__builtin_altivec_vsrab",
+    "llvm.ppc.altivec.vsrah" => "__builtin_altivec_vsrah",
+    "llvm.ppc.altivec.vsraw" => "__builtin_altivec_vsraw",
+    "llvm.ppc.altivec.vsrb" => "__builtin_altivec_vsrb",
+    "llvm.ppc.altivec.vsrdbi" => "__builtin_altivec_vsrdbi",
+    "llvm.ppc.altivec.vsrh" => "__builtin_altivec_vsrh",
+    "llvm.ppc.altivec.vsro" => "__builtin_altivec_vsro",
+    "llvm.ppc.altivec.vsrw" => "__builtin_altivec_vsrw",
+    "llvm.ppc.altivec.vstribl" => "__builtin_altivec_vstribl",
+    "llvm.ppc.altivec.vstribl.p" => "__builtin_altivec_vstribl_p",
+    "llvm.ppc.altivec.vstribr" => "__builtin_altivec_vstribr",
+    "llvm.ppc.altivec.vstribr.p" => "__builtin_altivec_vstribr_p",
+    "llvm.ppc.altivec.vstrihl" => "__builtin_altivec_vstrihl",
+    "llvm.ppc.altivec.vstrihl.p" => "__builtin_altivec_vstrihl_p",
+    "llvm.ppc.altivec.vstrihr" => "__builtin_altivec_vstrihr",
+    "llvm.ppc.altivec.vstrihr.p" => "__builtin_altivec_vstrihr_p",
+    "llvm.ppc.altivec.vsubcuw" => "__builtin_altivec_vsubcuw",
+    "llvm.ppc.altivec.vsubecuq" => "__builtin_altivec_vsubecuq",
+    "llvm.ppc.altivec.vsubeuqm" => "__builtin_altivec_vsubeuqm",
+    "llvm.ppc.altivec.vsubsbs" => "__builtin_altivec_vsubsbs",
+    "llvm.ppc.altivec.vsubshs" => "__builtin_altivec_vsubshs",
+    "llvm.ppc.altivec.vsubsws" => "__builtin_altivec_vsubsws",
+    "llvm.ppc.altivec.vsububs" => "__builtin_altivec_vsububs",
+    "llvm.ppc.altivec.vsubuhs" => "__builtin_altivec_vsubuhs",
+    "llvm.ppc.altivec.vsubuws" => "__builtin_altivec_vsubuws",
+    "llvm.ppc.altivec.vsum2sws" => "__builtin_altivec_vsum2sws",
+    "llvm.ppc.altivec.vsum4sbs" => "__builtin_altivec_vsum4sbs",
+    "llvm.ppc.altivec.vsum4shs" => "__builtin_altivec_vsum4shs",
+    "llvm.ppc.altivec.vsum4ubs" => "__builtin_altivec_vsum4ubs",
+    "llvm.ppc.altivec.vsumsws" => "__builtin_altivec_vsumsws",
+    "llvm.ppc.altivec.vupkhpx" => "__builtin_altivec_vupkhpx",
+    "llvm.ppc.altivec.vupkhsb" => "__builtin_altivec_vupkhsb",
+    "llvm.ppc.altivec.vupkhsh" => "__builtin_altivec_vupkhsh",
+    "llvm.ppc.altivec.vupkhsw" => "__builtin_altivec_vupkhsw",
+    "llvm.ppc.altivec.vupklpx" => "__builtin_altivec_vupklpx",
+    "llvm.ppc.altivec.vupklsb" => "__builtin_altivec_vupklsb",
+    "llvm.ppc.altivec.vupklsh" => "__builtin_altivec_vupklsh",
+    "llvm.ppc.altivec.vupklsw" => "__builtin_altivec_vupklsw",
+    "llvm.ppc.bcdadd" => "__builtin_ppc_bcdadd",
+    "llvm.ppc.bcdadd.p" => "__builtin_ppc_bcdadd_p",
+    "llvm.ppc.bcdsub" => "__builtin_ppc_bcdsub",
+    "llvm.ppc.bcdsub.p" => "__builtin_ppc_bcdsub_p",
+    "llvm.ppc.bpermd" => "__builtin_bpermd",
+    "llvm.ppc.cfuged" => "__builtin_cfuged",
+    "llvm.ppc.cmpeqb" => "__builtin_ppc_cmpeqb",
+    "llvm.ppc.cmprb" => "__builtin_ppc_cmprb",
+    "llvm.ppc.cntlzdm" => "__builtin_cntlzdm",
+    "llvm.ppc.cnttzdm" => "__builtin_cnttzdm",
+    "llvm.ppc.compare.exp.eq" => "__builtin_ppc_compare_exp_eq",
+    "llvm.ppc.compare.exp.gt" => "__builtin_ppc_compare_exp_gt",
+    "llvm.ppc.compare.exp.lt" => "__builtin_ppc_compare_exp_lt",
+    "llvm.ppc.compare.exp.uo" => "__builtin_ppc_compare_exp_uo",
+    "llvm.ppc.darn" => "__builtin_darn",
+    "llvm.ppc.darn32" => "__builtin_darn_32",
+    "llvm.ppc.darnraw" => "__builtin_darn_raw",
+    "llvm.ppc.dcbf" => "__builtin_dcbf",
+    "llvm.ppc.dcbfl" => "__builtin_ppc_dcbfl",
+    "llvm.ppc.dcbflp" => "__builtin_ppc_dcbflp",
+    "llvm.ppc.dcbst" => "__builtin_ppc_dcbst",
+    "llvm.ppc.dcbt" => "__builtin_ppc_dcbt",
+    "llvm.ppc.dcbtst" => "__builtin_ppc_dcbtst",
+    "llvm.ppc.dcbtstt" => "__builtin_ppc_dcbtstt",
+    "llvm.ppc.dcbtt" => "__builtin_ppc_dcbtt",
+    "llvm.ppc.dcbz" => "__builtin_ppc_dcbz",
+    "llvm.ppc.divde" => "__builtin_divde",
+    "llvm.ppc.divdeu" => "__builtin_divdeu",
+    "llvm.ppc.divf128.round.to.odd" => "__builtin_divf128_round_to_odd",
+    "llvm.ppc.divwe" => "__builtin_divwe",
+    "llvm.ppc.divweu" => "__builtin_divweu",
+    "llvm.ppc.eieio" => "__builtin_ppc_eieio",
+    "llvm.ppc.extract.exp" => "__builtin_ppc_extract_exp",
+    "llvm.ppc.extract.sig" => "__builtin_ppc_extract_sig",
+    "llvm.ppc.fcfid" => "__builtin_ppc_fcfid",
+    "llvm.ppc.fcfud" => "__builtin_ppc_fcfud",
+    "llvm.ppc.fctid" => "__builtin_ppc_fctid",
+    "llvm.ppc.fctidz" => "__builtin_ppc_fctidz",
+    "llvm.ppc.fctiw" => "__builtin_ppc_fctiw",
+    "llvm.ppc.fctiwz" => "__builtin_ppc_fctiwz",
+    "llvm.ppc.fctudz" => "__builtin_ppc_fctudz",
+    "llvm.ppc.fctuwz" => "__builtin_ppc_fctuwz",
+    "llvm.ppc.fmaf128.round.to.odd" => "__builtin_fmaf128_round_to_odd",
+    "llvm.ppc.fmsub" => "__builtin_ppc_fmsub",
+    "llvm.ppc.fmsubs" => "__builtin_ppc_fmsubs",
+    "llvm.ppc.fnmadd" => "__builtin_ppc_fnmadd",
+    "llvm.ppc.fnmadds" => "__builtin_ppc_fnmadds",
+    "llvm.ppc.fre" => "__builtin_ppc_fre",
+    "llvm.ppc.fres" => "__builtin_ppc_fres",
+    "llvm.ppc.frsqrte" => "__builtin_ppc_frsqrte",
+    "llvm.ppc.frsqrtes" => "__builtin_ppc_frsqrtes",
+    "llvm.ppc.fsel" => "__builtin_ppc_fsel",
+    "llvm.ppc.fsels" => "__builtin_ppc_fsels",
+    "llvm.ppc.get.texasr" => "__builtin_get_texasr",
+    "llvm.ppc.get.texasru" => "__builtin_get_texasru",
+    "llvm.ppc.get.tfhar" => "__builtin_get_tfhar",
+    "llvm.ppc.get.tfiar" => "__builtin_get_tfiar",
+    "llvm.ppc.icbt" => "__builtin_ppc_icbt",
+    "llvm.ppc.insert.exp" => "__builtin_ppc_insert_exp",
+    "llvm.ppc.iospace.eieio" => "__builtin_ppc_iospace_eieio",
+    "llvm.ppc.iospace.lwsync" => "__builtin_ppc_iospace_lwsync",
+    "llvm.ppc.iospace.sync" => "__builtin_ppc_iospace_sync",
+    "llvm.ppc.isync" => "__builtin_ppc_isync",
+    "llvm.ppc.load4r" => "__builtin_ppc_load4r",
+    "llvm.ppc.load8r" => "__builtin_ppc_load8r",
+    "llvm.ppc.lwsync" => "__builtin_ppc_lwsync",
+    "llvm.ppc.maddhd" => "__builtin_ppc_maddhd",
+    "llvm.ppc.maddhdu" => "__builtin_ppc_maddhdu",
+    "llvm.ppc.maddld" => "__builtin_ppc_maddld",
+    "llvm.ppc.mfmsr" => "__builtin_ppc_mfmsr",
+    "llvm.ppc.mftbu" => "__builtin_ppc_mftbu",
+    "llvm.ppc.mtfsb0" => "__builtin_ppc_mtfsb0",
+    "llvm.ppc.mtfsb1" => "__builtin_ppc_mtfsb1",
+    "llvm.ppc.mtfsfi" => "__builtin_ppc_mtfsfi",
+    "llvm.ppc.mtmsr" => "__builtin_ppc_mtmsr",
+    "llvm.ppc.mulf128.round.to.odd" => "__builtin_mulf128_round_to_odd",
+    "llvm.ppc.mulhd" => "__builtin_ppc_mulhd",
+    "llvm.ppc.mulhdu" => "__builtin_ppc_mulhdu",
+    "llvm.ppc.mulhw" => "__builtin_ppc_mulhw",
+    "llvm.ppc.mulhwu" => "__builtin_ppc_mulhwu",
+    "llvm.ppc.pack.longdouble" => "__builtin_pack_longdouble",
+    "llvm.ppc.pdepd" => "__builtin_pdepd",
+    "llvm.ppc.pextd" => "__builtin_pextd",
+    "llvm.ppc.qpx.qvfabs" => "__builtin_qpx_qvfabs",
+    "llvm.ppc.qpx.qvfadd" => "__builtin_qpx_qvfadd",
+    "llvm.ppc.qpx.qvfadds" => "__builtin_qpx_qvfadds",
+    "llvm.ppc.qpx.qvfcfid" => "__builtin_qpx_qvfcfid",
+    "llvm.ppc.qpx.qvfcfids" => "__builtin_qpx_qvfcfids",
+    "llvm.ppc.qpx.qvfcfidu" => "__builtin_qpx_qvfcfidu",
+    "llvm.ppc.qpx.qvfcfidus" => "__builtin_qpx_qvfcfidus",
+    "llvm.ppc.qpx.qvfcmpeq" => "__builtin_qpx_qvfcmpeq",
+    "llvm.ppc.qpx.qvfcmpgt" => "__builtin_qpx_qvfcmpgt",
+    "llvm.ppc.qpx.qvfcmplt" => "__builtin_qpx_qvfcmplt",
+    "llvm.ppc.qpx.qvfcpsgn" => "__builtin_qpx_qvfcpsgn",
+    "llvm.ppc.qpx.qvfctid" => "__builtin_qpx_qvfctid",
+    "llvm.ppc.qpx.qvfctidu" => "__builtin_qpx_qvfctidu",
+    "llvm.ppc.qpx.qvfctiduz" => "__builtin_qpx_qvfctiduz",
+    "llvm.ppc.qpx.qvfctidz" => "__builtin_qpx_qvfctidz",
+    "llvm.ppc.qpx.qvfctiw" => "__builtin_qpx_qvfctiw",
+    "llvm.ppc.qpx.qvfctiwu" => "__builtin_qpx_qvfctiwu",
+    "llvm.ppc.qpx.qvfctiwuz" => "__builtin_qpx_qvfctiwuz",
+    "llvm.ppc.qpx.qvfctiwz" => "__builtin_qpx_qvfctiwz",
+    "llvm.ppc.qpx.qvflogical" => "__builtin_qpx_qvflogical",
+    "llvm.ppc.qpx.qvfmadd" => "__builtin_qpx_qvfmadd",
+    "llvm.ppc.qpx.qvfmadds" => "__builtin_qpx_qvfmadds",
+    "llvm.ppc.qpx.qvfmsub" => "__builtin_qpx_qvfmsub",
+    "llvm.ppc.qpx.qvfmsubs" => "__builtin_qpx_qvfmsubs",
+    "llvm.ppc.qpx.qvfmul" => "__builtin_qpx_qvfmul",
+    "llvm.ppc.qpx.qvfmuls" => "__builtin_qpx_qvfmuls",
+    "llvm.ppc.qpx.qvfnabs" => "__builtin_qpx_qvfnabs",
+    "llvm.ppc.qpx.qvfneg" => "__builtin_qpx_qvfneg",
+    "llvm.ppc.qpx.qvfnmadd" => "__builtin_qpx_qvfnmadd",
+    "llvm.ppc.qpx.qvfnmadds" => "__builtin_qpx_qvfnmadds",
+    "llvm.ppc.qpx.qvfnmsub" => "__builtin_qpx_qvfnmsub",
+    "llvm.ppc.qpx.qvfnmsubs" => "__builtin_qpx_qvfnmsubs",
+    "llvm.ppc.qpx.qvfperm" => "__builtin_qpx_qvfperm",
+    "llvm.ppc.qpx.qvfre" => "__builtin_qpx_qvfre",
+    "llvm.ppc.qpx.qvfres" => "__builtin_qpx_qvfres",
+    "llvm.ppc.qpx.qvfrim" => "__builtin_qpx_qvfrim",
+    "llvm.ppc.qpx.qvfrin" => "__builtin_qpx_qvfrin",
+    "llvm.ppc.qpx.qvfrip" => "__builtin_qpx_qvfrip",
+    "llvm.ppc.qpx.qvfriz" => "__builtin_qpx_qvfriz",
+    "llvm.ppc.qpx.qvfrsp" => "__builtin_qpx_qvfrsp",
+    "llvm.ppc.qpx.qvfrsqrte" => "__builtin_qpx_qvfrsqrte",
+    "llvm.ppc.qpx.qvfrsqrtes" => "__builtin_qpx_qvfrsqrtes",
+    "llvm.ppc.qpx.qvfsel" => "__builtin_qpx_qvfsel",
+    "llvm.ppc.qpx.qvfsub" => "__builtin_qpx_qvfsub",
+    "llvm.ppc.qpx.qvfsubs" => "__builtin_qpx_qvfsubs",
+    "llvm.ppc.qpx.qvftstnan" => "__builtin_qpx_qvftstnan",
+    "llvm.ppc.qpx.qvfxmadd" => "__builtin_qpx_qvfxmadd",
+    "llvm.ppc.qpx.qvfxmadds" => "__builtin_qpx_qvfxmadds",
+    "llvm.ppc.qpx.qvfxmul" => "__builtin_qpx_qvfxmul",
+    "llvm.ppc.qpx.qvfxmuls" => "__builtin_qpx_qvfxmuls",
+    "llvm.ppc.qpx.qvfxxcpnmadd" => "__builtin_qpx_qvfxxcpnmadd",
+    "llvm.ppc.qpx.qvfxxcpnmadds" => "__builtin_qpx_qvfxxcpnmadds",
+    "llvm.ppc.qpx.qvfxxmadd" => "__builtin_qpx_qvfxxmadd",
+    "llvm.ppc.qpx.qvfxxmadds" => "__builtin_qpx_qvfxxmadds",
+    "llvm.ppc.qpx.qvfxxnpmadd" => "__builtin_qpx_qvfxxnpmadd",
+    "llvm.ppc.qpx.qvfxxnpmadds" => "__builtin_qpx_qvfxxnpmadds",
+    "llvm.ppc.qpx.qvgpci" => "__builtin_qpx_qvgpci",
+    "llvm.ppc.qpx.qvlfcd" => "__builtin_qpx_qvlfcd",
+    "llvm.ppc.qpx.qvlfcda" => "__builtin_qpx_qvlfcda",
+    "llvm.ppc.qpx.qvlfcs" => "__builtin_qpx_qvlfcs",
+    "llvm.ppc.qpx.qvlfcsa" => "__builtin_qpx_qvlfcsa",
+    "llvm.ppc.qpx.qvlfd" => "__builtin_qpx_qvlfd",
+    "llvm.ppc.qpx.qvlfda" => "__builtin_qpx_qvlfda",
+    "llvm.ppc.qpx.qvlfiwa" => "__builtin_qpx_qvlfiwa",
+    "llvm.ppc.qpx.qvlfiwaa" => "__builtin_qpx_qvlfiwaa",
+    "llvm.ppc.qpx.qvlfiwz" => "__builtin_qpx_qvlfiwz",
+    "llvm.ppc.qpx.qvlfiwza" => "__builtin_qpx_qvlfiwza",
+    "llvm.ppc.qpx.qvlfs" => "__builtin_qpx_qvlfs",
+    "llvm.ppc.qpx.qvlfsa" => "__builtin_qpx_qvlfsa",
+    "llvm.ppc.qpx.qvlpcld" => "__builtin_qpx_qvlpcld",
+    "llvm.ppc.qpx.qvlpcls" => "__builtin_qpx_qvlpcls",
+    "llvm.ppc.qpx.qvlpcrd" => "__builtin_qpx_qvlpcrd",
+    "llvm.ppc.qpx.qvlpcrs" => "__builtin_qpx_qvlpcrs",
+    "llvm.ppc.qpx.qvstfcd" => "__builtin_qpx_qvstfcd",
+    "llvm.ppc.qpx.qvstfcda" => "__builtin_qpx_qvstfcda",
+    "llvm.ppc.qpx.qvstfcs" => "__builtin_qpx_qvstfcs",
+    "llvm.ppc.qpx.qvstfcsa" => "__builtin_qpx_qvstfcsa",
+    "llvm.ppc.qpx.qvstfd" => "__builtin_qpx_qvstfd",
+    "llvm.ppc.qpx.qvstfda" => "__builtin_qpx_qvstfda",
+    "llvm.ppc.qpx.qvstfiw" => "__builtin_qpx_qvstfiw",
+    "llvm.ppc.qpx.qvstfiwa" => "__builtin_qpx_qvstfiwa",
+    "llvm.ppc.qpx.qvstfs" => "__builtin_qpx_qvstfs",
+    "llvm.ppc.qpx.qvstfsa" => "__builtin_qpx_qvstfsa",
+    "llvm.ppc.readflm" => "__builtin_readflm",
+    "llvm.ppc.scalar.extract.expq" => "__builtin_vsx_scalar_extract_expq",
+    "llvm.ppc.scalar.insert.exp.qp" => "__builtin_vsx_scalar_insert_exp_qp",
+    "llvm.ppc.set.texasr" => "__builtin_set_texasr",
+    "llvm.ppc.set.texasru" => "__builtin_set_texasru",
+    "llvm.ppc.set.tfhar" => "__builtin_set_tfhar",
+    "llvm.ppc.set.tfiar" => "__builtin_set_tfiar",
+    "llvm.ppc.setb" => "__builtin_ppc_setb",
+    "llvm.ppc.setflm" => "__builtin_setflm",
+    "llvm.ppc.setrnd" => "__builtin_setrnd",
+    "llvm.ppc.sqrtf128.round.to.odd" => "__builtin_sqrtf128_round_to_odd",
+    "llvm.ppc.stbcx" => "__builtin_ppc_stbcx",
+    "llvm.ppc.stdcx" => "__builtin_ppc_stdcx",
+    "llvm.ppc.stfiw" => "__builtin_ppc_stfiw",
+    "llvm.ppc.store2r" => "__builtin_ppc_store2r",
+    "llvm.ppc.store4r" => "__builtin_ppc_store4r",
+    "llvm.ppc.store8r" => "__builtin_ppc_store8r",
+    "llvm.ppc.stwcx" => "__builtin_ppc_stwcx",
+    "llvm.ppc.subf128.round.to.odd" => "__builtin_subf128_round_to_odd",
+    "llvm.ppc.sync" => "__builtin_ppc_sync",
+    "llvm.ppc.tabort" => "__builtin_tabort",
+    "llvm.ppc.tabortdc" => "__builtin_tabortdc",
+    "llvm.ppc.tabortdci" => "__builtin_tabortdci",
+    "llvm.ppc.tabortwc" => "__builtin_tabortwc",
+    "llvm.ppc.tabortwci" => "__builtin_tabortwci",
+    "llvm.ppc.tbegin" => "__builtin_tbegin",
+    "llvm.ppc.tcheck" => "__builtin_tcheck",
+    "llvm.ppc.tdw" => "__builtin_ppc_tdw",
+    "llvm.ppc.tend" => "__builtin_tend",
+    "llvm.ppc.tendall" => "__builtin_tendall",
+    "llvm.ppc.trap" => "__builtin_ppc_trap",
+    "llvm.ppc.trapd" => "__builtin_ppc_trapd",
+    "llvm.ppc.trechkpt" => "__builtin_trechkpt",
+    "llvm.ppc.treclaim" => "__builtin_treclaim",
+    "llvm.ppc.tresume" => "__builtin_tresume",
+    "llvm.ppc.truncf128.round.to.odd" => "__builtin_truncf128_round_to_odd",
+    "llvm.ppc.tsr" => "__builtin_tsr",
+    "llvm.ppc.tsuspend" => "__builtin_tsuspend",
+    "llvm.ppc.ttest" => "__builtin_ttest",
+    "llvm.ppc.tw" => "__builtin_ppc_tw",
+    "llvm.ppc.unpack.longdouble" => "__builtin_unpack_longdouble",
+    "llvm.ppc.vsx.xsmaxdp" => "__builtin_vsx_xsmaxdp",
+    "llvm.ppc.vsx.xsmindp" => "__builtin_vsx_xsmindp",
+    "llvm.ppc.vsx.xvcmpeqdp" => "__builtin_vsx_xvcmpeqdp",
+    "llvm.ppc.vsx.xvcmpeqdp.p" => "__builtin_vsx_xvcmpeqdp_p",
+    "llvm.ppc.vsx.xvcmpeqsp" => "__builtin_vsx_xvcmpeqsp",
+    "llvm.ppc.vsx.xvcmpeqsp.p" => "__builtin_vsx_xvcmpeqsp_p",
+    "llvm.ppc.vsx.xvcmpgedp" => "__builtin_vsx_xvcmpgedp",
+    "llvm.ppc.vsx.xvcmpgedp.p" => "__builtin_vsx_xvcmpgedp_p",
+    "llvm.ppc.vsx.xvcmpgesp" => "__builtin_vsx_xvcmpgesp",
+    "llvm.ppc.vsx.xvcmpgesp.p" => "__builtin_vsx_xvcmpgesp_p",
+    "llvm.ppc.vsx.xvcmpgtdp" => "__builtin_vsx_xvcmpgtdp",
+    "llvm.ppc.vsx.xvcmpgtdp.p" => "__builtin_vsx_xvcmpgtdp_p",
+    "llvm.ppc.vsx.xvcmpgtsp" => "__builtin_vsx_xvcmpgtsp",
+    "llvm.ppc.vsx.xvcmpgtsp.p" => "__builtin_vsx_xvcmpgtsp_p",
+    "llvm.ppc.vsx.xvdivdp" => "__builtin_vsx_xvdivdp",
+    "llvm.ppc.vsx.xvdivsp" => "__builtin_vsx_xvdivsp",
+    "llvm.ppc.vsx.xvmaxdp" => "__builtin_vsx_xvmaxdp",
+    "llvm.ppc.vsx.xvmaxsp" => "__builtin_vsx_xvmaxsp",
+    "llvm.ppc.vsx.xvmindp" => "__builtin_vsx_xvmindp",
+    "llvm.ppc.vsx.xvminsp" => "__builtin_vsx_xvminsp",
+    "llvm.ppc.vsx.xvredp" => "__builtin_vsx_xvredp",
+    "llvm.ppc.vsx.xvresp" => "__builtin_vsx_xvresp",
+    "llvm.ppc.vsx.xvrsqrtedp" => "__builtin_vsx_xvrsqrtedp",
+    "llvm.ppc.vsx.xvrsqrtesp" => "__builtin_vsx_xvrsqrtesp",
+    "llvm.ppc.vsx.xxblendvb" => "__builtin_vsx_xxblendvb",
+    "llvm.ppc.vsx.xxblendvd" => "__builtin_vsx_xxblendvd",
+    "llvm.ppc.vsx.xxblendvh" => "__builtin_vsx_xxblendvh",
+    "llvm.ppc.vsx.xxblendvw" => "__builtin_vsx_xxblendvw",
+    "llvm.ppc.vsx.xxleqv" => "__builtin_vsx_xxleqv",
+    "llvm.ppc.vsx.xxpermx" => "__builtin_vsx_xxpermx",
+    // ptx
+    "llvm.ptx.bar.sync" => "__builtin_ptx_bar_sync",
+    "llvm.ptx.read.clock" => "__builtin_ptx_read_clock",
+    "llvm.ptx.read.clock64" => "__builtin_ptx_read_clock64",
+    "llvm.ptx.read.gridid" => "__builtin_ptx_read_gridid",
+    "llvm.ptx.read.laneid" => "__builtin_ptx_read_laneid",
+    "llvm.ptx.read.lanemask.eq" => "__builtin_ptx_read_lanemask_eq",
+    "llvm.ptx.read.lanemask.ge" => "__builtin_ptx_read_lanemask_ge",
+    "llvm.ptx.read.lanemask.gt" => "__builtin_ptx_read_lanemask_gt",
+    "llvm.ptx.read.lanemask.le" => "__builtin_ptx_read_lanemask_le",
+    "llvm.ptx.read.lanemask.lt" => "__builtin_ptx_read_lanemask_lt",
+    "llvm.ptx.read.nsmid" => "__builtin_ptx_read_nsmid",
+    "llvm.ptx.read.nwarpid" => "__builtin_ptx_read_nwarpid",
+    "llvm.ptx.read.pm0" => "__builtin_ptx_read_pm0",
+    "llvm.ptx.read.pm1" => "__builtin_ptx_read_pm1",
+    "llvm.ptx.read.pm2" => "__builtin_ptx_read_pm2",
+    "llvm.ptx.read.pm3" => "__builtin_ptx_read_pm3",
+    "llvm.ptx.read.smid" => "__builtin_ptx_read_smid",
+    "llvm.ptx.read.warpid" => "__builtin_ptx_read_warpid",
+    // s390
+    "llvm.s390.efpc" => "__builtin_s390_efpc",
+    "llvm.s390.etnd" => "__builtin_tx_nesting_depth",
+    "llvm.s390.lcbb" => "__builtin_s390_lcbb",
+    "llvm.s390.ppa.txassist" => "__builtin_tx_assist",
+    "llvm.s390.sfpc" => "__builtin_s390_sfpc",
+    "llvm.s390.tend" => "__builtin_tend",
+    "llvm.s390.vcfn" => "__builtin_s390_vcfn",
+    "llvm.s390.vclfnhs" => "__builtin_s390_vclfnhs",
+    "llvm.s390.vclfnls" => "__builtin_s390_vclfnls",
+    "llvm.s390.vcnf" => "__builtin_s390_vcnf",
+    "llvm.s390.vcrnfs" => "__builtin_s390_vcrnfs",
+    "llvm.s390.vlbb" => "__builtin_s390_vlbb",
+    "llvm.s390.vll" => "__builtin_s390_vll",
+    "llvm.s390.vlrl" => "__builtin_s390_vlrl",
+    "llvm.s390.vmslg" => "__builtin_s390_vmslg",
+    "llvm.s390.vpdi" => "__builtin_s390_vpdi",
+    "llvm.s390.vperm" => "__builtin_s390_vperm",
+    "llvm.s390.vsld" => "__builtin_s390_vsld",
+    "llvm.s390.vsldb" => "__builtin_s390_vsldb",
+    "llvm.s390.vsrd" => "__builtin_s390_vsrd",
+    "llvm.s390.vstl" => "__builtin_s390_vstl",
+    "llvm.s390.vstrl" => "__builtin_s390_vstrl",
+    // ve
+    "llvm.ve.vl.extract.vm512l" => "__builtin_ve_vl_extract_vm512l",
+    "llvm.ve.vl.extract.vm512u" => "__builtin_ve_vl_extract_vm512u",
+    "llvm.ve.vl.insert.vm512l" => "__builtin_ve_vl_insert_vm512l",
+    "llvm.ve.vl.insert.vm512u" => "__builtin_ve_vl_insert_vm512u",
+    "llvm.ve.vl.pack.f32a" => "__builtin_ve_vl_pack_f32a",
+    "llvm.ve.vl.pack.f32p" => "__builtin_ve_vl_pack_f32p",
+    // x86
+    "llvm.x86.3dnow.pavgusb" => "__builtin_ia32_pavgusb",
+    "llvm.x86.3dnow.pf2id" => "__builtin_ia32_pf2id",
+    "llvm.x86.3dnow.pfacc" => "__builtin_ia32_pfacc",
+    "llvm.x86.3dnow.pfadd" => "__builtin_ia32_pfadd",
+    "llvm.x86.3dnow.pfcmpeq" => "__builtin_ia32_pfcmpeq",
+    "llvm.x86.3dnow.pfcmpge" => "__builtin_ia32_pfcmpge",
+    "llvm.x86.3dnow.pfcmpgt" => "__builtin_ia32_pfcmpgt",
+    "llvm.x86.3dnow.pfmax" => "__builtin_ia32_pfmax",
+    "llvm.x86.3dnow.pfmin" => "__builtin_ia32_pfmin",
+    "llvm.x86.3dnow.pfmul" => "__builtin_ia32_pfmul",
+    "llvm.x86.3dnow.pfrcp" => "__builtin_ia32_pfrcp",
+    "llvm.x86.3dnow.pfrcpit1" => "__builtin_ia32_pfrcpit1",
+    "llvm.x86.3dnow.pfrcpit2" => "__builtin_ia32_pfrcpit2",
+    "llvm.x86.3dnow.pfrsqit1" => "__builtin_ia32_pfrsqit1",
+    "llvm.x86.3dnow.pfrsqrt" => "__builtin_ia32_pfrsqrt",
+    "llvm.x86.3dnow.pfsub" => "__builtin_ia32_pfsub",
+    "llvm.x86.3dnow.pfsubr" => "__builtin_ia32_pfsubr",
+    "llvm.x86.3dnow.pi2fd" => "__builtin_ia32_pi2fd",
+    "llvm.x86.3dnow.pmulhrw" => "__builtin_ia32_pmulhrw",
+    "llvm.x86.3dnowa.pf2iw" => "__builtin_ia32_pf2iw",
+    "llvm.x86.3dnowa.pfnacc" => "__builtin_ia32_pfnacc",
+    "llvm.x86.3dnowa.pfpnacc" => "__builtin_ia32_pfpnacc",
+    "llvm.x86.3dnowa.pi2fw" => "__builtin_ia32_pi2fw",
+    "llvm.x86.addcarry.u32" => "__builtin_ia32_addcarry_u32",
+    "llvm.x86.addcarry.u64" => "__builtin_ia32_addcarry_u64",
+    "llvm.x86.addcarryx.u32" => "__builtin_ia32_addcarryx_u32",
+    "llvm.x86.addcarryx.u64" => "__builtin_ia32_addcarryx_u64",
+    "llvm.x86.aesni.aesdec" => "__builtin_ia32_aesdec128",
+    "llvm.x86.aesni.aesdec.256" => "__builtin_ia32_aesdec256",
+    "llvm.x86.aesni.aesdec.512" => "__builtin_ia32_aesdec512",
+    "llvm.x86.aesni.aesdeclast" => "__builtin_ia32_aesdeclast128",
+    "llvm.x86.aesni.aesdeclast.256" => "__builtin_ia32_aesdeclast256",
+    "llvm.x86.aesni.aesdeclast.512" => "__builtin_ia32_aesdeclast512",
+    "llvm.x86.aesni.aesenc" => "__builtin_ia32_aesenc128",
+    "llvm.x86.aesni.aesenc.256" => "__builtin_ia32_aesenc256",
+    "llvm.x86.aesni.aesenc.512" => "__builtin_ia32_aesenc512",
+    "llvm.x86.aesni.aesenclast" => "__builtin_ia32_aesenclast128",
+    "llvm.x86.aesni.aesenclast.256" => "__builtin_ia32_aesenclast256",
+    "llvm.x86.aesni.aesenclast.512" => "__builtin_ia32_aesenclast512",
+    "llvm.x86.aesni.aesimc" => "__builtin_ia32_aesimc128",
+    "llvm.x86.aesni.aeskeygenassist" => "__builtin_ia32_aeskeygenassist128",
+    "llvm.x86.avx.addsub.pd.256" => "__builtin_ia32_addsubpd256",
+    "llvm.x86.avx.addsub.ps.256" => "__builtin_ia32_addsubps256",
+    "llvm.x86.avx.blend.pd.256" => "__builtin_ia32_blendpd256",
+    "llvm.x86.avx.blend.ps.256" => "__builtin_ia32_blendps256",
+    "llvm.x86.avx.blendv.pd.256" => "__builtin_ia32_blendvpd256",
+    "llvm.x86.avx.blendv.ps.256" => "__builtin_ia32_blendvps256",
+    "llvm.x86.avx.cmp.pd.256" => "__builtin_ia32_cmppd256",
+    "llvm.x86.avx.cmp.ps.256" => "__builtin_ia32_cmpps256",
+    "llvm.x86.avx.cvt.pd2.ps.256" => "__builtin_ia32_cvtpd2ps256",
+    "llvm.x86.avx.cvt.pd2dq.256" => "__builtin_ia32_cvtpd2dq256",
+    "llvm.x86.avx.cvt.ps2.pd.256" => "__builtin_ia32_cvtps2pd256",
+    "llvm.x86.avx.cvt.ps2dq.256" => "__builtin_ia32_cvtps2dq256",
+    "llvm.x86.avx.cvtdq2.pd.256" => "__builtin_ia32_cvtdq2pd256",
+    "llvm.x86.avx.cvtdq2.ps.256" => "__builtin_ia32_cvtdq2ps256",
+    "llvm.x86.avx.cvtt.pd2dq.256" => "__builtin_ia32_cvttpd2dq256",
+    "llvm.x86.avx.cvtt.ps2dq.256" => "__builtin_ia32_cvttps2dq256",
+    "llvm.x86.avx.dp.ps.256" => "__builtin_ia32_dpps256",
+    "llvm.x86.avx.hadd.pd.256" => "__builtin_ia32_haddpd256",
+    "llvm.x86.avx.hadd.ps.256" => "__builtin_ia32_haddps256",
+    "llvm.x86.avx.hsub.pd.256" => "__builtin_ia32_hsubpd256",
+    "llvm.x86.avx.hsub.ps.256" => "__builtin_ia32_hsubps256",
+    "llvm.x86.avx.ldu.dq.256" => "__builtin_ia32_lddqu256",
+    "llvm.x86.avx.maskload.pd" => "__builtin_ia32_maskloadpd",
+    "llvm.x86.avx.maskload.pd.256" => "__builtin_ia32_maskloadpd256",
+    "llvm.x86.avx.maskload.ps" => "__builtin_ia32_maskloadps",
+    "llvm.x86.avx.maskload.ps.256" => "__builtin_ia32_maskloadps256",
+    "llvm.x86.avx.maskstore.pd" => "__builtin_ia32_maskstorepd",
+    "llvm.x86.avx.maskstore.pd.256" => "__builtin_ia32_maskstorepd256",
+    "llvm.x86.avx.maskstore.ps" => "__builtin_ia32_maskstoreps",
+    "llvm.x86.avx.maskstore.ps.256" => "__builtin_ia32_maskstoreps256",
+    "llvm.x86.avx.max.pd.256" => "__builtin_ia32_maxpd256",
+    "llvm.x86.avx.max.ps.256" => "__builtin_ia32_maxps256",
+    "llvm.x86.avx.min.pd.256" => "__builtin_ia32_minpd256",
+    "llvm.x86.avx.min.ps.256" => "__builtin_ia32_minps256",
+    "llvm.x86.avx.movmsk.pd.256" => "__builtin_ia32_movmskpd256",
+    "llvm.x86.avx.movmsk.ps.256" => "__builtin_ia32_movmskps256",
+    "llvm.x86.avx.ptestc.256" => "__builtin_ia32_ptestc256",
+    "llvm.x86.avx.ptestnzc.256" => "__builtin_ia32_ptestnzc256",
+    "llvm.x86.avx.ptestz.256" => "__builtin_ia32_ptestz256",
+    "llvm.x86.avx.rcp.ps.256" => "__builtin_ia32_rcpps256",
+    "llvm.x86.avx.round.pd.256" => "__builtin_ia32_roundpd256",
+    "llvm.x86.avx.round.ps.256" => "__builtin_ia32_roundps256",
+    "llvm.x86.avx.rsqrt.ps.256" => "__builtin_ia32_rsqrtps256",
+    "llvm.x86.avx.sqrt.pd.256" => "__builtin_ia32_sqrtpd256",
+    "llvm.x86.avx.sqrt.ps.256" => "__builtin_ia32_sqrtps256",
+    "llvm.x86.avx.storeu.dq.256" => "__builtin_ia32_storedqu256",
+    "llvm.x86.avx.storeu.pd.256" => "__builtin_ia32_storeupd256",
+    "llvm.x86.avx.storeu.ps.256" => "__builtin_ia32_storeups256",
+    "llvm.x86.avx.vbroadcastf128.pd.256" => "__builtin_ia32_vbroadcastf128_pd256",
+    "llvm.x86.avx.vbroadcastf128.ps.256" => "__builtin_ia32_vbroadcastf128_ps256",
+    "llvm.x86.avx.vextractf128.pd.256" => "__builtin_ia32_vextractf128_pd256",
+    "llvm.x86.avx.vextractf128.ps.256" => "__builtin_ia32_vextractf128_ps256",
+    "llvm.x86.avx.vextractf128.si.256" => "__builtin_ia32_vextractf128_si256",
+    "llvm.x86.avx.vinsertf128.pd.256" => "__builtin_ia32_vinsertf128_pd256",
+    "llvm.x86.avx.vinsertf128.ps.256" => "__builtin_ia32_vinsertf128_ps256",
+    "llvm.x86.avx.vinsertf128.si.256" => "__builtin_ia32_vinsertf128_si256",
+    "llvm.x86.avx.vperm2f128.pd.256" => "__builtin_ia32_vperm2f128_pd256",
+    "llvm.x86.avx.vperm2f128.ps.256" => "__builtin_ia32_vperm2f128_ps256",
+    "llvm.x86.avx.vperm2f128.si.256" => "__builtin_ia32_vperm2f128_si256",
+    "llvm.x86.avx.vpermilvar.pd" => "__builtin_ia32_vpermilvarpd",
+    "llvm.x86.avx.vpermilvar.pd.256" => "__builtin_ia32_vpermilvarpd256",
+    "llvm.x86.avx.vpermilvar.ps" => "__builtin_ia32_vpermilvarps",
+    "llvm.x86.avx.vpermilvar.ps.256" => "__builtin_ia32_vpermilvarps256",
+    "llvm.x86.avx.vtestc.pd" => "__builtin_ia32_vtestcpd",
+    "llvm.x86.avx.vtestc.pd.256" => "__builtin_ia32_vtestcpd256",
+    "llvm.x86.avx.vtestc.ps" => "__builtin_ia32_vtestcps",
+    "llvm.x86.avx.vtestc.ps.256" => "__builtin_ia32_vtestcps256",
+    "llvm.x86.avx.vtestnzc.pd" => "__builtin_ia32_vtestnzcpd",
+    "llvm.x86.avx.vtestnzc.pd.256" => "__builtin_ia32_vtestnzcpd256",
+    "llvm.x86.avx.vtestnzc.ps" => "__builtin_ia32_vtestnzcps",
+    "llvm.x86.avx.vtestnzc.ps.256" => "__builtin_ia32_vtestnzcps256",
+    "llvm.x86.avx.vtestz.pd" => "__builtin_ia32_vtestzpd",
+    "llvm.x86.avx.vtestz.pd.256" => "__builtin_ia32_vtestzpd256",
+    "llvm.x86.avx.vtestz.ps" => "__builtin_ia32_vtestzps",
+    "llvm.x86.avx.vtestz.ps.256" => "__builtin_ia32_vtestzps256",
+    "llvm.x86.avx.vzeroall" => "__builtin_ia32_vzeroall",
+    "llvm.x86.avx.vzeroupper" => "__builtin_ia32_vzeroupper",
+    "llvm.x86.avx2.gather.d.d" => "__builtin_ia32_gatherd_d",
+    "llvm.x86.avx2.gather.d.d.256" => "__builtin_ia32_gatherd_d256",
+    "llvm.x86.avx2.gather.d.pd" => "__builtin_ia32_gatherd_pd",
+    "llvm.x86.avx2.gather.d.pd.256" => "__builtin_ia32_gatherd_pd256",
+    "llvm.x86.avx2.gather.d.ps" => "__builtin_ia32_gatherd_ps",
+    "llvm.x86.avx2.gather.d.ps.256" => "__builtin_ia32_gatherd_ps256",
+    "llvm.x86.avx2.gather.d.q" => "__builtin_ia32_gatherd_q",
+    "llvm.x86.avx2.gather.d.q.256" => "__builtin_ia32_gatherd_q256",
+    "llvm.x86.avx2.gather.q.d" => "__builtin_ia32_gatherq_d",
+    "llvm.x86.avx2.gather.q.d.256" => "__builtin_ia32_gatherq_d256",
+    "llvm.x86.avx2.gather.q.pd" => "__builtin_ia32_gatherq_pd",
+    "llvm.x86.avx2.gather.q.pd.256" => "__builtin_ia32_gatherq_pd256",
+    "llvm.x86.avx2.gather.q.ps" => "__builtin_ia32_gatherq_ps",
+    "llvm.x86.avx2.gather.q.ps.256" => "__builtin_ia32_gatherq_ps256",
+    "llvm.x86.avx2.gather.q.q" => "__builtin_ia32_gatherq_q",
+    "llvm.x86.avx2.gather.q.q.256" => "__builtin_ia32_gatherq_q256",
+    "llvm.x86.avx2.maskload.d" => "__builtin_ia32_maskloadd",
+    "llvm.x86.avx2.maskload.d.256" => "__builtin_ia32_maskloadd256",
+    "llvm.x86.avx2.maskload.q" => "__builtin_ia32_maskloadq",
+    "llvm.x86.avx2.maskload.q.256" => "__builtin_ia32_maskloadq256",
+    "llvm.x86.avx2.maskstore.d" => "__builtin_ia32_maskstored",
+    "llvm.x86.avx2.maskstore.d.256" => "__builtin_ia32_maskstored256",
+    "llvm.x86.avx2.maskstore.q" => "__builtin_ia32_maskstoreq",
+    "llvm.x86.avx2.maskstore.q.256" => "__builtin_ia32_maskstoreq256",
+    "llvm.x86.avx2.movntdqa" => "__builtin_ia32_movntdqa256",
+    "llvm.x86.avx2.mpsadbw" => "__builtin_ia32_mpsadbw256",
+    "llvm.x86.avx2.pabs.b" => "__builtin_ia32_pabsb256",
+    "llvm.x86.avx2.pabs.d" => "__builtin_ia32_pabsd256",
+    "llvm.x86.avx2.pabs.w" => "__builtin_ia32_pabsw256",
+    "llvm.x86.avx2.packssdw" => "__builtin_ia32_packssdw256",
+    "llvm.x86.avx2.packsswb" => "__builtin_ia32_packsswb256",
+    "llvm.x86.avx2.packusdw" => "__builtin_ia32_packusdw256",
+    "llvm.x86.avx2.packuswb" => "__builtin_ia32_packuswb256",
+    "llvm.x86.avx2.padds.b" => "__builtin_ia32_paddsb256",
+    "llvm.x86.avx2.padds.w" => "__builtin_ia32_paddsw256",
+    "llvm.x86.avx2.paddus.b" => "__builtin_ia32_paddusb256",
+    "llvm.x86.avx2.paddus.w" => "__builtin_ia32_paddusw256",
+    "llvm.x86.avx2.pavg.b" => "__builtin_ia32_pavgb256",
+    "llvm.x86.avx2.pavg.w" => "__builtin_ia32_pavgw256",
+    "llvm.x86.avx2.pblendd.128" => "__builtin_ia32_pblendd128",
+    "llvm.x86.avx2.pblendd.256" => "__builtin_ia32_pblendd256",
+    "llvm.x86.avx2.pblendvb" => "__builtin_ia32_pblendvb256",
+    "llvm.x86.avx2.pblendw" => "__builtin_ia32_pblendw256",
+    "llvm.x86.avx2.pbroadcastb.128" => "__builtin_ia32_pbroadcastb128",
+    "llvm.x86.avx2.pbroadcastb.256" => "__builtin_ia32_pbroadcastb256",
+    "llvm.x86.avx2.pbroadcastd.128" => "__builtin_ia32_pbroadcastd128",
+    "llvm.x86.avx2.pbroadcastd.256" => "__builtin_ia32_pbroadcastd256",
+    "llvm.x86.avx2.pbroadcastq.128" => "__builtin_ia32_pbroadcastq128",
+    "llvm.x86.avx2.pbroadcastq.256" => "__builtin_ia32_pbroadcastq256",
+    "llvm.x86.avx2.pbroadcastw.128" => "__builtin_ia32_pbroadcastw128",
+    "llvm.x86.avx2.pbroadcastw.256" => "__builtin_ia32_pbroadcastw256",
+    "llvm.x86.avx2.permd" => "__builtin_ia32_permvarsi256",
+    "llvm.x86.avx2.permps" => "__builtin_ia32_permvarsf256",
+    "llvm.x86.avx2.phadd.d" => "__builtin_ia32_phaddd256",
+    "llvm.x86.avx2.phadd.sw" => "__builtin_ia32_phaddsw256",
+    "llvm.x86.avx2.phadd.w" => "__builtin_ia32_phaddw256",
+    "llvm.x86.avx2.phsub.d" => "__builtin_ia32_phsubd256",
+    "llvm.x86.avx2.phsub.sw" => "__builtin_ia32_phsubsw256",
+    "llvm.x86.avx2.phsub.w" => "__builtin_ia32_phsubw256",
+    "llvm.x86.avx2.pmadd.ub.sw" => "__builtin_ia32_pmaddubsw256",
+    "llvm.x86.avx2.pmadd.wd" => "__builtin_ia32_pmaddwd256",
+    "llvm.x86.avx2.pmaxs.b" => "__builtin_ia32_pmaxsb256",
+    "llvm.x86.avx2.pmaxs.d" => "__builtin_ia32_pmaxsd256",
+    "llvm.x86.avx2.pmaxs.w" => "__builtin_ia32_pmaxsw256",
+    "llvm.x86.avx2.pmaxu.b" => "__builtin_ia32_pmaxub256",
+    "llvm.x86.avx2.pmaxu.d" => "__builtin_ia32_pmaxud256",
+    "llvm.x86.avx2.pmaxu.w" => "__builtin_ia32_pmaxuw256",
+    "llvm.x86.avx2.pmins.b" => "__builtin_ia32_pminsb256",
+    "llvm.x86.avx2.pmins.d" => "__builtin_ia32_pminsd256",
+    "llvm.x86.avx2.pmins.w" => "__builtin_ia32_pminsw256",
+    "llvm.x86.avx2.pminu.b" => "__builtin_ia32_pminub256",
+    "llvm.x86.avx2.pminu.d" => "__builtin_ia32_pminud256",
+    "llvm.x86.avx2.pminu.w" => "__builtin_ia32_pminuw256",
+    "llvm.x86.avx2.pmovmskb" => "__builtin_ia32_pmovmskb256",
+    "llvm.x86.avx2.pmovsxbd" => "__builtin_ia32_pmovsxbd256",
+    "llvm.x86.avx2.pmovsxbq" => "__builtin_ia32_pmovsxbq256",
+    "llvm.x86.avx2.pmovsxbw" => "__builtin_ia32_pmovsxbw256",
+    "llvm.x86.avx2.pmovsxdq" => "__builtin_ia32_pmovsxdq256",
+    "llvm.x86.avx2.pmovsxwd" => "__builtin_ia32_pmovsxwd256",
+    "llvm.x86.avx2.pmovsxwq" => "__builtin_ia32_pmovsxwq256",
+    "llvm.x86.avx2.pmovzxbd" => "__builtin_ia32_pmovzxbd256",
+    "llvm.x86.avx2.pmovzxbq" => "__builtin_ia32_pmovzxbq256",
+    "llvm.x86.avx2.pmovzxbw" => "__builtin_ia32_pmovzxbw256",
+    "llvm.x86.avx2.pmovzxdq" => "__builtin_ia32_pmovzxdq256",
+    "llvm.x86.avx2.pmovzxwd" => "__builtin_ia32_pmovzxwd256",
+    "llvm.x86.avx2.pmovzxwq" => "__builtin_ia32_pmovzxwq256",
+    "llvm.x86.avx2.pmul.dq" => "__builtin_ia32_pmuldq256",
+    "llvm.x86.avx2.pmul.hr.sw" => "__builtin_ia32_pmulhrsw256",
+    "llvm.x86.avx2.pmulh.w" => "__builtin_ia32_pmulhw256",
+    "llvm.x86.avx2.pmulhu.w" => "__builtin_ia32_pmulhuw256",
+    "llvm.x86.avx2.pmulu.dq" => "__builtin_ia32_pmuludq256",
+    "llvm.x86.avx2.psad.bw" => "__builtin_ia32_psadbw256",
+    "llvm.x86.avx2.pshuf.b" => "__builtin_ia32_pshufb256",
+    "llvm.x86.avx2.psign.b" => "__builtin_ia32_psignb256",
+    "llvm.x86.avx2.psign.d" => "__builtin_ia32_psignd256",
+    "llvm.x86.avx2.psign.w" => "__builtin_ia32_psignw256",
+    "llvm.x86.avx2.psll.d" => "__builtin_ia32_pslld256",
+    "llvm.x86.avx2.psll.dq" => "__builtin_ia32_pslldqi256",
+    "llvm.x86.avx2.psll.dq.bs" => "__builtin_ia32_pslldqi256_byteshift",
+    "llvm.x86.avx2.psll.q" => "__builtin_ia32_psllq256",
+    "llvm.x86.avx2.psll.w" => "__builtin_ia32_psllw256",
+    "llvm.x86.avx2.pslli.d" => "__builtin_ia32_pslldi256",
+    "llvm.x86.avx2.pslli.q" => "__builtin_ia32_psllqi256",
+    "llvm.x86.avx2.pslli.w" => "__builtin_ia32_psllwi256",
+    "llvm.x86.avx2.psllv.d" => "__builtin_ia32_psllv4si",
+    "llvm.x86.avx2.psllv.d.256" => "__builtin_ia32_psllv8si",
+    "llvm.x86.avx2.psllv.q" => "__builtin_ia32_psllv2di",
+    "llvm.x86.avx2.psllv.q.256" => "__builtin_ia32_psllv4di",
+    "llvm.x86.avx2.psra.d" => "__builtin_ia32_psrad256",
+    "llvm.x86.avx2.psra.w" => "__builtin_ia32_psraw256",
+    "llvm.x86.avx2.psrai.d" => "__builtin_ia32_psradi256",
+    "llvm.x86.avx2.psrai.w" => "__builtin_ia32_psrawi256",
+    "llvm.x86.avx2.psrav.d" => "__builtin_ia32_psrav4si",
+    "llvm.x86.avx2.psrav.d.256" => "__builtin_ia32_psrav8si",
+    "llvm.x86.avx2.psrl.d" => "__builtin_ia32_psrld256",
+    "llvm.x86.avx2.psrl.dq" => "__builtin_ia32_psrldqi256",
+    "llvm.x86.avx2.psrl.dq.bs" => "__builtin_ia32_psrldqi256_byteshift",
+    "llvm.x86.avx2.psrl.q" => "__builtin_ia32_psrlq256",
+    "llvm.x86.avx2.psrl.w" => "__builtin_ia32_psrlw256",
+    "llvm.x86.avx2.psrli.d" => "__builtin_ia32_psrldi256",
+    "llvm.x86.avx2.psrli.q" => "__builtin_ia32_psrlqi256",
+    "llvm.x86.avx2.psrli.w" => "__builtin_ia32_psrlwi256",
+    "llvm.x86.avx2.psrlv.d" => "__builtin_ia32_psrlv4si",
+    "llvm.x86.avx2.psrlv.d.256" => "__builtin_ia32_psrlv8si",
+    "llvm.x86.avx2.psrlv.q" => "__builtin_ia32_psrlv2di",
+    "llvm.x86.avx2.psrlv.q.256" => "__builtin_ia32_psrlv4di",
+    "llvm.x86.avx2.psubs.b" => "__builtin_ia32_psubsb256",
+    "llvm.x86.avx2.psubs.w" => "__builtin_ia32_psubsw256",
+    "llvm.x86.avx2.psubus.b" => "__builtin_ia32_psubusb256",
+    "llvm.x86.avx2.psubus.w" => "__builtin_ia32_psubusw256",
+    "llvm.x86.avx2.vbroadcast.sd.pd.256" => "__builtin_ia32_vbroadcastsd_pd256",
+    "llvm.x86.avx2.vbroadcast.ss.ps" => "__builtin_ia32_vbroadcastss_ps",
+    "llvm.x86.avx2.vbroadcast.ss.ps.256" => "__builtin_ia32_vbroadcastss_ps256",
+    "llvm.x86.avx2.vextracti128" => "__builtin_ia32_extract128i256",
+    "llvm.x86.avx2.vinserti128" => "__builtin_ia32_insert128i256",
+    "llvm.x86.avx2.vperm2i128" => "__builtin_ia32_permti256",
+    "llvm.x86.avx512.add.pd.512" => "__builtin_ia32_addpd512",
+    "llvm.x86.avx512.add.ps.512" => "__builtin_ia32_addps512",
+    "llvm.x86.avx512.broadcastmb.128" => "__builtin_ia32_broadcastmb128",
+    "llvm.x86.avx512.broadcastmb.256" => "__builtin_ia32_broadcastmb256",
+    "llvm.x86.avx512.broadcastmb.512" => "__builtin_ia32_broadcastmb512",
+    "llvm.x86.avx512.broadcastmw.128" => "__builtin_ia32_broadcastmw128",
+    "llvm.x86.avx512.broadcastmw.256" => "__builtin_ia32_broadcastmw256",
+    "llvm.x86.avx512.broadcastmw.512" => "__builtin_ia32_broadcastmw512",
+    "llvm.x86.avx512.conflict.d.128" => "__builtin_ia32_vpconflictsi_128",
+    "llvm.x86.avx512.conflict.d.256" => "__builtin_ia32_vpconflictsi_256",
+    "llvm.x86.avx512.conflict.d.512" => "__builtin_ia32_vpconflictsi_512",
+    "llvm.x86.avx512.conflict.q.128" => "__builtin_ia32_vpconflictdi_128",
+    "llvm.x86.avx512.conflict.q.256" => "__builtin_ia32_vpconflictdi_256",
+    "llvm.x86.avx512.conflict.q.512" => "__builtin_ia32_vpconflictdi_512",
+    "llvm.x86.avx512.cvtb2mask.128" => "__builtin_ia32_cvtb2mask128",
+    "llvm.x86.avx512.cvtb2mask.256" => "__builtin_ia32_cvtb2mask256",
+    "llvm.x86.avx512.cvtb2mask.512" => "__builtin_ia32_cvtb2mask512",
+    "llvm.x86.avx512.cvtd2mask.128" => "__builtin_ia32_cvtd2mask128",
+    "llvm.x86.avx512.cvtd2mask.256" => "__builtin_ia32_cvtd2mask256",
+    "llvm.x86.avx512.cvtd2mask.512" => "__builtin_ia32_cvtd2mask512",
+    "llvm.x86.avx512.cvtmask2b.128" => "__builtin_ia32_cvtmask2b128",
+    "llvm.x86.avx512.cvtmask2b.256" => "__builtin_ia32_cvtmask2b256",
+    "llvm.x86.avx512.cvtmask2b.512" => "__builtin_ia32_cvtmask2b512",
+    "llvm.x86.avx512.cvtmask2d.128" => "__builtin_ia32_cvtmask2d128",
+    "llvm.x86.avx512.cvtmask2d.256" => "__builtin_ia32_cvtmask2d256",
+    "llvm.x86.avx512.cvtmask2d.512" => "__builtin_ia32_cvtmask2d512",
+    "llvm.x86.avx512.cvtmask2q.128" => "__builtin_ia32_cvtmask2q128",
+    "llvm.x86.avx512.cvtmask2q.256" => "__builtin_ia32_cvtmask2q256",
+    "llvm.x86.avx512.cvtmask2q.512" => "__builtin_ia32_cvtmask2q512",
+    "llvm.x86.avx512.cvtmask2w.128" => "__builtin_ia32_cvtmask2w128",
+    "llvm.x86.avx512.cvtmask2w.256" => "__builtin_ia32_cvtmask2w256",
+    "llvm.x86.avx512.cvtmask2w.512" => "__builtin_ia32_cvtmask2w512",
+    "llvm.x86.avx512.cvtq2mask.128" => "__builtin_ia32_cvtq2mask128",
+    "llvm.x86.avx512.cvtq2mask.256" => "__builtin_ia32_cvtq2mask256",
+    "llvm.x86.avx512.cvtq2mask.512" => "__builtin_ia32_cvtq2mask512",
+    "llvm.x86.avx512.cvtsd2usi" => "__builtin_ia32_cvtsd2usi",
+    "llvm.x86.avx512.cvtsd2usi64" => "__builtin_ia32_cvtsd2usi64",
+    "llvm.x86.avx512.cvtsi2sd32" => "__builtin_ia32_cvtsi2sd32",
+    "llvm.x86.avx512.cvtsi2sd64" => "__builtin_ia32_cvtsi2sd64",
+    "llvm.x86.avx512.cvtsi2ss32" => "__builtin_ia32_cvtsi2ss32",
+    "llvm.x86.avx512.cvtsi2ss64" => "__builtin_ia32_cvtsi2ss64",
+    "llvm.x86.avx512.cvtss2usi" => "__builtin_ia32_cvtss2usi",
+    "llvm.x86.avx512.cvtss2usi64" => "__builtin_ia32_cvtss2usi64",
+    "llvm.x86.avx512.cvttsd2si" => "__builtin_ia32_vcvttsd2si32",
+    "llvm.x86.avx512.cvttsd2si64" => "__builtin_ia32_vcvttsd2si64",
+    "llvm.x86.avx512.cvttsd2usi" => "__builtin_ia32_vcvttsd2usi32",
+    // [DUPLICATE]: "llvm.x86.avx512.cvttsd2usi" => "__builtin_ia32_cvttsd2usi",
+    "llvm.x86.avx512.cvttsd2usi64" => "__builtin_ia32_vcvttsd2usi64",
+    // [DUPLICATE]: "llvm.x86.avx512.cvttsd2usi64" => "__builtin_ia32_cvttsd2usi64",
+    "llvm.x86.avx512.cvttss2si" => "__builtin_ia32_vcvttss2si32",
+    "llvm.x86.avx512.cvttss2si64" => "__builtin_ia32_vcvttss2si64",
+    "llvm.x86.avx512.cvttss2usi" => "__builtin_ia32_vcvttss2usi32",
+    // [DUPLICATE]: "llvm.x86.avx512.cvttss2usi" => "__builtin_ia32_cvttss2usi",
+    "llvm.x86.avx512.cvttss2usi64" => "__builtin_ia32_vcvttss2usi64",
+    // [DUPLICATE]: "llvm.x86.avx512.cvttss2usi64" => "__builtin_ia32_cvttss2usi64",
+    "llvm.x86.avx512.cvtusi2sd" => "__builtin_ia32_cvtusi2sd",
+    // [DUPLICATE]: "llvm.x86.avx512.cvtusi2sd" => "__builtin_ia32_cvtusi2sd32",
+    "llvm.x86.avx512.cvtusi2ss" => "__builtin_ia32_cvtusi2ss32",
+    // [DUPLICATE]: "llvm.x86.avx512.cvtusi2ss" => "__builtin_ia32_cvtusi2ss",
+    "llvm.x86.avx512.cvtusi642sd" => "__builtin_ia32_cvtusi2sd64",
+    // [DUPLICATE]: "llvm.x86.avx512.cvtusi642sd" => "__builtin_ia32_cvtusi642sd",
+    "llvm.x86.avx512.cvtusi642ss" => "__builtin_ia32_cvtusi2ss64",
+    // [DUPLICATE]: "llvm.x86.avx512.cvtusi642ss" => "__builtin_ia32_cvtusi642ss",
+    "llvm.x86.avx512.cvtw2mask.128" => "__builtin_ia32_cvtw2mask128",
+    "llvm.x86.avx512.cvtw2mask.256" => "__builtin_ia32_cvtw2mask256",
+    "llvm.x86.avx512.cvtw2mask.512" => "__builtin_ia32_cvtw2mask512",
+    "llvm.x86.avx512.dbpsadbw.128" => "__builtin_ia32_dbpsadbw128",
+    "llvm.x86.avx512.dbpsadbw.256" => "__builtin_ia32_dbpsadbw256",
+    "llvm.x86.avx512.dbpsadbw.512" => "__builtin_ia32_dbpsadbw512",
+    "llvm.x86.avx512.div.pd.512" => "__builtin_ia32_divpd512",
+    "llvm.x86.avx512.div.ps.512" => "__builtin_ia32_divps512",
+    "llvm.x86.avx512.exp2.pd" => "__builtin_ia32_exp2pd_mask",
+    "llvm.x86.avx512.exp2.ps" => "__builtin_ia32_exp2ps_mask",
+    "llvm.x86.avx512.gather.dpd.512" => "__builtin_ia32_gathersiv8df",
+    "llvm.x86.avx512.gather.dpi.512" => "__builtin_ia32_gathersiv16si",
+    "llvm.x86.avx512.gather.dpq.512" => "__builtin_ia32_gathersiv8di",
+    "llvm.x86.avx512.gather.dps.512" => "__builtin_ia32_gathersiv16sf",
+    "llvm.x86.avx512.gather.qpd.512" => "__builtin_ia32_gatherdiv8df",
+    "llvm.x86.avx512.gather.qpi.512" => "__builtin_ia32_gatherdiv16si",
+    "llvm.x86.avx512.gather.qpq.512" => "__builtin_ia32_gatherdiv8di",
+    "llvm.x86.avx512.gather.qps.512" => "__builtin_ia32_gatherdiv16sf",
+    "llvm.x86.avx512.gather3div2.df" => "__builtin_ia32_gather3div2df",
+    "llvm.x86.avx512.gather3div2.di" => "__builtin_ia32_gather3div2di",
+    "llvm.x86.avx512.gather3div4.df" => "__builtin_ia32_gather3div4df",
+    "llvm.x86.avx512.gather3div4.di" => "__builtin_ia32_gather3div4di",
+    "llvm.x86.avx512.gather3div4.sf" => "__builtin_ia32_gather3div4sf",
+    "llvm.x86.avx512.gather3div4.si" => "__builtin_ia32_gather3div4si",
+    "llvm.x86.avx512.gather3div8.sf" => "__builtin_ia32_gather3div8sf",
+    "llvm.x86.avx512.gather3div8.si" => "__builtin_ia32_gather3div8si",
+    "llvm.x86.avx512.gather3siv2.df" => "__builtin_ia32_gather3siv2df",
+    "llvm.x86.avx512.gather3siv2.di" => "__builtin_ia32_gather3siv2di",
+    "llvm.x86.avx512.gather3siv4.df" => "__builtin_ia32_gather3siv4df",
+    "llvm.x86.avx512.gather3siv4.di" => "__builtin_ia32_gather3siv4di",
+    "llvm.x86.avx512.gather3siv4.sf" => "__builtin_ia32_gather3siv4sf",
+    "llvm.x86.avx512.gather3siv4.si" => "__builtin_ia32_gather3siv4si",
+    "llvm.x86.avx512.gather3siv8.sf" => "__builtin_ia32_gather3siv8sf",
+    "llvm.x86.avx512.gather3siv8.si" => "__builtin_ia32_gather3siv8si",
+    "llvm.x86.avx512.gatherpf.dpd.512" => "__builtin_ia32_gatherpfdpd",
+    "llvm.x86.avx512.gatherpf.dps.512" => "__builtin_ia32_gatherpfdps",
+    "llvm.x86.avx512.gatherpf.qpd.512" => "__builtin_ia32_gatherpfqpd",
+    "llvm.x86.avx512.gatherpf.qps.512" => "__builtin_ia32_gatherpfqps",
+    "llvm.x86.avx512.kand.w" => "__builtin_ia32_kandhi",
+    "llvm.x86.avx512.kandn.w" => "__builtin_ia32_kandnhi",
+    "llvm.x86.avx512.knot.w" => "__builtin_ia32_knothi",
+    "llvm.x86.avx512.kor.w" => "__builtin_ia32_korhi",
+    "llvm.x86.avx512.kortestc.w" => "__builtin_ia32_kortestchi",
+    "llvm.x86.avx512.kortestz.w" => "__builtin_ia32_kortestzhi",
+    "llvm.x86.avx512.kunpck.bw" => "__builtin_ia32_kunpckhi",
+    "llvm.x86.avx512.kunpck.dq" => "__builtin_ia32_kunpckdi",
+    "llvm.x86.avx512.kunpck.wd" => "__builtin_ia32_kunpcksi",
+    "llvm.x86.avx512.kxnor.w" => "__builtin_ia32_kxnorhi",
+    "llvm.x86.avx512.kxor.w" => "__builtin_ia32_kxorhi",
+    "llvm.x86.avx512.mask.add.pd.128" => "__builtin_ia32_addpd128_mask",
+    "llvm.x86.avx512.mask.add.pd.256" => "__builtin_ia32_addpd256_mask",
+    "llvm.x86.avx512.mask.add.pd.512" => "__builtin_ia32_addpd512_mask",
+    "llvm.x86.avx512.mask.add.ps.128" => "__builtin_ia32_addps128_mask",
+    "llvm.x86.avx512.mask.add.ps.256" => "__builtin_ia32_addps256_mask",
+    "llvm.x86.avx512.mask.add.ps.512" => "__builtin_ia32_addps512_mask",
+    "llvm.x86.avx512.mask.add.sd.round" => "__builtin_ia32_addsd_round_mask",
+    "llvm.x86.avx512.mask.add.ss.round" => "__builtin_ia32_addss_round_mask",
+    "llvm.x86.avx512.mask.and.pd.128" => "__builtin_ia32_andpd128_mask",
+    "llvm.x86.avx512.mask.and.pd.256" => "__builtin_ia32_andpd256_mask",
+    "llvm.x86.avx512.mask.and.pd.512" => "__builtin_ia32_andpd512_mask",
+    "llvm.x86.avx512.mask.and.ps.128" => "__builtin_ia32_andps128_mask",
+    "llvm.x86.avx512.mask.and.ps.256" => "__builtin_ia32_andps256_mask",
+    "llvm.x86.avx512.mask.and.ps.512" => "__builtin_ia32_andps512_mask",
+    "llvm.x86.avx512.mask.andn.pd.128" => "__builtin_ia32_andnpd128_mask",
+    "llvm.x86.avx512.mask.andn.pd.256" => "__builtin_ia32_andnpd256_mask",
+    "llvm.x86.avx512.mask.andn.pd.512" => "__builtin_ia32_andnpd512_mask",
+    "llvm.x86.avx512.mask.andn.ps.128" => "__builtin_ia32_andnps128_mask",
+    "llvm.x86.avx512.mask.andn.ps.256" => "__builtin_ia32_andnps256_mask",
+    "llvm.x86.avx512.mask.andn.ps.512" => "__builtin_ia32_andnps512_mask",
+    "llvm.x86.avx512.mask.blend.d.512" => "__builtin_ia32_blendmd_512_mask",
+    "llvm.x86.avx512.mask.blend.pd.512" => "__builtin_ia32_blendmpd_512_mask",
+    "llvm.x86.avx512.mask.blend.ps.512" => "__builtin_ia32_blendmps_512_mask",
+    "llvm.x86.avx512.mask.blend.q.512" => "__builtin_ia32_blendmq_512_mask",
+    "llvm.x86.avx512.mask.broadcastf32x2.256" => "__builtin_ia32_broadcastf32x2_256_mask",
+    "llvm.x86.avx512.mask.broadcastf32x2.512" => "__builtin_ia32_broadcastf32x2_512_mask",
+    "llvm.x86.avx512.mask.broadcastf32x4.256" => "__builtin_ia32_broadcastf32x4_256_mask",
+    "llvm.x86.avx512.mask.broadcastf32x4.512" => "__builtin_ia32_broadcastf32x4_512",
+    "llvm.x86.avx512.mask.broadcastf32x8.512" => "__builtin_ia32_broadcastf32x8_512_mask",
+    "llvm.x86.avx512.mask.broadcastf64x2.256" => "__builtin_ia32_broadcastf64x2_256_mask",
+    "llvm.x86.avx512.mask.broadcastf64x2.512" => "__builtin_ia32_broadcastf64x2_512_mask",
+    "llvm.x86.avx512.mask.broadcastf64x4.512" => "__builtin_ia32_broadcastf64x4_512",
+    "llvm.x86.avx512.mask.broadcasti32x2.128" => "__builtin_ia32_broadcasti32x2_128_mask",
+    "llvm.x86.avx512.mask.broadcasti32x2.256" => "__builtin_ia32_broadcasti32x2_256_mask",
+    "llvm.x86.avx512.mask.broadcasti32x2.512" => "__builtin_ia32_broadcasti32x2_512_mask",
+    "llvm.x86.avx512.mask.broadcasti32x4.256" => "__builtin_ia32_broadcasti32x4_256_mask",
+    "llvm.x86.avx512.mask.broadcasti32x4.512" => "__builtin_ia32_broadcasti32x4_512",
+    "llvm.x86.avx512.mask.broadcasti32x8.512" => "__builtin_ia32_broadcasti32x8_512_mask",
+    "llvm.x86.avx512.mask.broadcasti64x2.256" => "__builtin_ia32_broadcasti64x2_256_mask",
+    "llvm.x86.avx512.mask.broadcasti64x2.512" => "__builtin_ia32_broadcasti64x2_512_mask",
+    "llvm.x86.avx512.mask.broadcasti64x4.512" => "__builtin_ia32_broadcasti64x4_512",
+    "llvm.x86.avx512.mask.cmp.pd.128" => "__builtin_ia32_cmppd128_mask",
+    "llvm.x86.avx512.mask.cmp.pd.256" => "__builtin_ia32_cmppd256_mask",
+    "llvm.x86.avx512.mask.cmp.pd.512" => "__builtin_ia32_cmppd512_mask",
+    "llvm.x86.avx512.mask.cmp.ps.128" => "__builtin_ia32_cmpps128_mask",
+    "llvm.x86.avx512.mask.cmp.ps.256" => "__builtin_ia32_cmpps256_mask",
+    "llvm.x86.avx512.mask.cmp.ps.512" => "__builtin_ia32_cmpps512_mask",
+    "llvm.x86.avx512.mask.cmp.sd" => "__builtin_ia32_cmpsd_mask",
+    "llvm.x86.avx512.mask.cmp.ss" => "__builtin_ia32_cmpss_mask",
+    "llvm.x86.avx512.mask.compress.d.128" => "__builtin_ia32_compresssi128_mask",
+    "llvm.x86.avx512.mask.compress.d.256" => "__builtin_ia32_compresssi256_mask",
+    "llvm.x86.avx512.mask.compress.d.512" => "__builtin_ia32_compresssi512_mask",
+    "llvm.x86.avx512.mask.compress.pd.128" => "__builtin_ia32_compressdf128_mask",
+    "llvm.x86.avx512.mask.compress.pd.256" => "__builtin_ia32_compressdf256_mask",
+    "llvm.x86.avx512.mask.compress.pd.512" => "__builtin_ia32_compressdf512_mask",
+    "llvm.x86.avx512.mask.compress.ps.128" => "__builtin_ia32_compresssf128_mask",
+    "llvm.x86.avx512.mask.compress.ps.256" => "__builtin_ia32_compresssf256_mask",
+    "llvm.x86.avx512.mask.compress.ps.512" => "__builtin_ia32_compresssf512_mask",
+    "llvm.x86.avx512.mask.compress.q.128" => "__builtin_ia32_compressdi128_mask",
+    "llvm.x86.avx512.mask.compress.q.256" => "__builtin_ia32_compressdi256_mask",
+    "llvm.x86.avx512.mask.compress.q.512" => "__builtin_ia32_compressdi512_mask",
+    "llvm.x86.avx512.mask.compress.store.d.128" => "__builtin_ia32_compressstoresi128_mask",
+    "llvm.x86.avx512.mask.compress.store.d.256" => "__builtin_ia32_compressstoresi256_mask",
+    "llvm.x86.avx512.mask.compress.store.d.512" => "__builtin_ia32_compressstoresi512_mask",
+    "llvm.x86.avx512.mask.compress.store.pd.128" => "__builtin_ia32_compressstoredf128_mask",
+    "llvm.x86.avx512.mask.compress.store.pd.256" => "__builtin_ia32_compressstoredf256_mask",
+    "llvm.x86.avx512.mask.compress.store.pd.512" => "__builtin_ia32_compressstoredf512_mask",
+    "llvm.x86.avx512.mask.compress.store.ps.128" => "__builtin_ia32_compressstoresf128_mask",
+    "llvm.x86.avx512.mask.compress.store.ps.256" => "__builtin_ia32_compressstoresf256_mask",
+    "llvm.x86.avx512.mask.compress.store.ps.512" => "__builtin_ia32_compressstoresf512_mask",
+    "llvm.x86.avx512.mask.compress.store.q.128" => "__builtin_ia32_compressstoredi128_mask",
+    "llvm.x86.avx512.mask.compress.store.q.256" => "__builtin_ia32_compressstoredi256_mask",
+    "llvm.x86.avx512.mask.compress.store.q.512" => "__builtin_ia32_compressstoredi512_mask",
+    "llvm.x86.avx512.mask.conflict.d.128" => "__builtin_ia32_vpconflictsi_128_mask",
+    "llvm.x86.avx512.mask.conflict.d.256" => "__builtin_ia32_vpconflictsi_256_mask",
+    "llvm.x86.avx512.mask.conflict.d.512" => "__builtin_ia32_vpconflictsi_512_mask",
+    "llvm.x86.avx512.mask.conflict.q.128" => "__builtin_ia32_vpconflictdi_128_mask",
+    "llvm.x86.avx512.mask.conflict.q.256" => "__builtin_ia32_vpconflictdi_256_mask",
+    "llvm.x86.avx512.mask.conflict.q.512" => "__builtin_ia32_vpconflictdi_512_mask",
+    "llvm.x86.avx512.mask.cvtdq2pd.128" => "__builtin_ia32_cvtdq2pd128_mask",
+    "llvm.x86.avx512.mask.cvtdq2pd.256" => "__builtin_ia32_cvtdq2pd256_mask",
+    "llvm.x86.avx512.mask.cvtdq2pd.512" => "__builtin_ia32_cvtdq2pd512_mask",
+    "llvm.x86.avx512.mask.cvtdq2ps.128" => "__builtin_ia32_cvtdq2ps128_mask",
+    "llvm.x86.avx512.mask.cvtdq2ps.256" => "__builtin_ia32_cvtdq2ps256_mask",
+    "llvm.x86.avx512.mask.cvtdq2ps.512" => "__builtin_ia32_cvtdq2ps512_mask",
+    "llvm.x86.avx512.mask.cvtpd2dq.128" => "__builtin_ia32_cvtpd2dq128_mask",
+    "llvm.x86.avx512.mask.cvtpd2dq.256" => "__builtin_ia32_cvtpd2dq256_mask",
+    "llvm.x86.avx512.mask.cvtpd2dq.512" => "__builtin_ia32_cvtpd2dq512_mask",
+    "llvm.x86.avx512.mask.cvtpd2ps" => "__builtin_ia32_cvtpd2ps_mask",
+    "llvm.x86.avx512.mask.cvtpd2ps.256" => "__builtin_ia32_cvtpd2ps256_mask",
+    "llvm.x86.avx512.mask.cvtpd2ps.512" => "__builtin_ia32_cvtpd2ps512_mask",
+    "llvm.x86.avx512.mask.cvtpd2qq.128" => "__builtin_ia32_cvtpd2qq128_mask",
+    "llvm.x86.avx512.mask.cvtpd2qq.256" => "__builtin_ia32_cvtpd2qq256_mask",
+    "llvm.x86.avx512.mask.cvtpd2qq.512" => "__builtin_ia32_cvtpd2qq512_mask",
+    "llvm.x86.avx512.mask.cvtpd2udq.128" => "__builtin_ia32_cvtpd2udq128_mask",
+    "llvm.x86.avx512.mask.cvtpd2udq.256" => "__builtin_ia32_cvtpd2udq256_mask",
+    "llvm.x86.avx512.mask.cvtpd2udq.512" => "__builtin_ia32_cvtpd2udq512_mask",
+    "llvm.x86.avx512.mask.cvtpd2uqq.128" => "__builtin_ia32_cvtpd2uqq128_mask",
+    "llvm.x86.avx512.mask.cvtpd2uqq.256" => "__builtin_ia32_cvtpd2uqq256_mask",
+    "llvm.x86.avx512.mask.cvtpd2uqq.512" => "__builtin_ia32_cvtpd2uqq512_mask",
+    "llvm.x86.avx512.mask.cvtps2dq.128" => "__builtin_ia32_cvtps2dq128_mask",
+    "llvm.x86.avx512.mask.cvtps2dq.256" => "__builtin_ia32_cvtps2dq256_mask",
+    "llvm.x86.avx512.mask.cvtps2dq.512" => "__builtin_ia32_cvtps2dq512_mask",
+    "llvm.x86.avx512.mask.cvtps2pd.128" => "__builtin_ia32_cvtps2pd128_mask",
+    "llvm.x86.avx512.mask.cvtps2pd.256" => "__builtin_ia32_cvtps2pd256_mask",
+    "llvm.x86.avx512.mask.cvtps2pd.512" => "__builtin_ia32_cvtps2pd512_mask",
+    "llvm.x86.avx512.mask.cvtps2qq.128" => "__builtin_ia32_cvtps2qq128_mask",
+    "llvm.x86.avx512.mask.cvtps2qq.256" => "__builtin_ia32_cvtps2qq256_mask",
+    "llvm.x86.avx512.mask.cvtps2qq.512" => "__builtin_ia32_cvtps2qq512_mask",
+    "llvm.x86.avx512.mask.cvtps2udq.128" => "__builtin_ia32_cvtps2udq128_mask",
+    "llvm.x86.avx512.mask.cvtps2udq.256" => "__builtin_ia32_cvtps2udq256_mask",
+    "llvm.x86.avx512.mask.cvtps2udq.512" => "__builtin_ia32_cvtps2udq512_mask",
+    "llvm.x86.avx512.mask.cvtps2uqq.128" => "__builtin_ia32_cvtps2uqq128_mask",
+    "llvm.x86.avx512.mask.cvtps2uqq.256" => "__builtin_ia32_cvtps2uqq256_mask",
+    "llvm.x86.avx512.mask.cvtps2uqq.512" => "__builtin_ia32_cvtps2uqq512_mask",
+    "llvm.x86.avx512.mask.cvtqq2pd.128" => "__builtin_ia32_cvtqq2pd128_mask",
+    "llvm.x86.avx512.mask.cvtqq2pd.256" => "__builtin_ia32_cvtqq2pd256_mask",
+    "llvm.x86.avx512.mask.cvtqq2pd.512" => "__builtin_ia32_cvtqq2pd512_mask",
+    "llvm.x86.avx512.mask.cvtqq2ps.128" => "__builtin_ia32_cvtqq2ps128_mask",
+    "llvm.x86.avx512.mask.cvtqq2ps.256" => "__builtin_ia32_cvtqq2ps256_mask",
+    "llvm.x86.avx512.mask.cvtqq2ps.512" => "__builtin_ia32_cvtqq2ps512_mask",
+    "llvm.x86.avx512.mask.cvtsd2ss.round" => "__builtin_ia32_cvtsd2ss_round_mask",
+    "llvm.x86.avx512.mask.cvtss2sd.round" => "__builtin_ia32_cvtss2sd_round_mask",
+    "llvm.x86.avx512.mask.cvttpd2dq.128" => "__builtin_ia32_cvttpd2dq128_mask",
+    "llvm.x86.avx512.mask.cvttpd2dq.256" => "__builtin_ia32_cvttpd2dq256_mask",
+    "llvm.x86.avx512.mask.cvttpd2dq.512" => "__builtin_ia32_cvttpd2dq512_mask",
+    "llvm.x86.avx512.mask.cvttpd2qq.128" => "__builtin_ia32_cvttpd2qq128_mask",
+    "llvm.x86.avx512.mask.cvttpd2qq.256" => "__builtin_ia32_cvttpd2qq256_mask",
+    "llvm.x86.avx512.mask.cvttpd2qq.512" => "__builtin_ia32_cvttpd2qq512_mask",
+    "llvm.x86.avx512.mask.cvttpd2udq.128" => "__builtin_ia32_cvttpd2udq128_mask",
+    "llvm.x86.avx512.mask.cvttpd2udq.256" => "__builtin_ia32_cvttpd2udq256_mask",
+    "llvm.x86.avx512.mask.cvttpd2udq.512" => "__builtin_ia32_cvttpd2udq512_mask",
+    "llvm.x86.avx512.mask.cvttpd2uqq.128" => "__builtin_ia32_cvttpd2uqq128_mask",
+    "llvm.x86.avx512.mask.cvttpd2uqq.256" => "__builtin_ia32_cvttpd2uqq256_mask",
+    "llvm.x86.avx512.mask.cvttpd2uqq.512" => "__builtin_ia32_cvttpd2uqq512_mask",
+    "llvm.x86.avx512.mask.cvttps2dq.128" => "__builtin_ia32_cvttps2dq128_mask",
+    "llvm.x86.avx512.mask.cvttps2dq.256" => "__builtin_ia32_cvttps2dq256_mask",
+    "llvm.x86.avx512.mask.cvttps2dq.512" => "__builtin_ia32_cvttps2dq512_mask",
+    "llvm.x86.avx512.mask.cvttps2qq.128" => "__builtin_ia32_cvttps2qq128_mask",
+    "llvm.x86.avx512.mask.cvttps2qq.256" => "__builtin_ia32_cvttps2qq256_mask",
+    "llvm.x86.avx512.mask.cvttps2qq.512" => "__builtin_ia32_cvttps2qq512_mask",
+    "llvm.x86.avx512.mask.cvttps2udq.128" => "__builtin_ia32_cvttps2udq128_mask",
+    "llvm.x86.avx512.mask.cvttps2udq.256" => "__builtin_ia32_cvttps2udq256_mask",
+    "llvm.x86.avx512.mask.cvttps2udq.512" => "__builtin_ia32_cvttps2udq512_mask",
+    "llvm.x86.avx512.mask.cvttps2uqq.128" => "__builtin_ia32_cvttps2uqq128_mask",
+    "llvm.x86.avx512.mask.cvttps2uqq.256" => "__builtin_ia32_cvttps2uqq256_mask",
+    "llvm.x86.avx512.mask.cvttps2uqq.512" => "__builtin_ia32_cvttps2uqq512_mask",
+    "llvm.x86.avx512.mask.cvtudq2pd.128" => "__builtin_ia32_cvtudq2pd128_mask",
+    "llvm.x86.avx512.mask.cvtudq2pd.256" => "__builtin_ia32_cvtudq2pd256_mask",
+    "llvm.x86.avx512.mask.cvtudq2pd.512" => "__builtin_ia32_cvtudq2pd512_mask",
+    "llvm.x86.avx512.mask.cvtudq2ps.128" => "__builtin_ia32_cvtudq2ps128_mask",
+    "llvm.x86.avx512.mask.cvtudq2ps.256" => "__builtin_ia32_cvtudq2ps256_mask",
+    "llvm.x86.avx512.mask.cvtudq2ps.512" => "__builtin_ia32_cvtudq2ps512_mask",
+    "llvm.x86.avx512.mask.cvtuqq2pd.128" => "__builtin_ia32_cvtuqq2pd128_mask",
+    "llvm.x86.avx512.mask.cvtuqq2pd.256" => "__builtin_ia32_cvtuqq2pd256_mask",
+    "llvm.x86.avx512.mask.cvtuqq2pd.512" => "__builtin_ia32_cvtuqq2pd512_mask",
+    "llvm.x86.avx512.mask.cvtuqq2ps.128" => "__builtin_ia32_cvtuqq2ps128_mask",
+    "llvm.x86.avx512.mask.cvtuqq2ps.256" => "__builtin_ia32_cvtuqq2ps256_mask",
+    "llvm.x86.avx512.mask.cvtuqq2ps.512" => "__builtin_ia32_cvtuqq2ps512_mask",
+    "llvm.x86.avx512.mask.dbpsadbw.128" => "__builtin_ia32_dbpsadbw128_mask",
+    "llvm.x86.avx512.mask.dbpsadbw.256" => "__builtin_ia32_dbpsadbw256_mask",
+    "llvm.x86.avx512.mask.dbpsadbw.512" => "__builtin_ia32_dbpsadbw512_mask",
+    "llvm.x86.avx512.mask.div.pd.128" => "__builtin_ia32_divpd_mask",
+    "llvm.x86.avx512.mask.div.pd.256" => "__builtin_ia32_divpd256_mask",
+    "llvm.x86.avx512.mask.div.pd.512" => "__builtin_ia32_divpd512_mask",
+    "llvm.x86.avx512.mask.div.ps.128" => "__builtin_ia32_divps_mask",
+    "llvm.x86.avx512.mask.div.ps.256" => "__builtin_ia32_divps256_mask",
+    "llvm.x86.avx512.mask.div.ps.512" => "__builtin_ia32_divps512_mask",
+    "llvm.x86.avx512.mask.div.sd.round" => "__builtin_ia32_divsd_round_mask",
+    "llvm.x86.avx512.mask.div.ss.round" => "__builtin_ia32_divss_round_mask",
+    "llvm.x86.avx512.mask.expand.d.128" => "__builtin_ia32_expandsi128_mask",
+    "llvm.x86.avx512.mask.expand.d.256" => "__builtin_ia32_expandsi256_mask",
+    "llvm.x86.avx512.mask.expand.d.512" => "__builtin_ia32_expandsi512_mask",
+    "llvm.x86.avx512.mask.expand.load.d.128" => "__builtin_ia32_expandloadsi128_mask",
+    "llvm.x86.avx512.mask.expand.load.d.256" => "__builtin_ia32_expandloadsi256_mask",
+    "llvm.x86.avx512.mask.expand.load.d.512" => "__builtin_ia32_expandloadsi512_mask",
+    "llvm.x86.avx512.mask.expand.load.pd.128" => "__builtin_ia32_expandloaddf128_mask",
+    "llvm.x86.avx512.mask.expand.load.pd.256" => "__builtin_ia32_expandloaddf256_mask",
+    "llvm.x86.avx512.mask.expand.load.pd.512" => "__builtin_ia32_expandloaddf512_mask",
+    "llvm.x86.avx512.mask.expand.load.ps.128" => "__builtin_ia32_expandloadsf128_mask",
+    "llvm.x86.avx512.mask.expand.load.ps.256" => "__builtin_ia32_expandloadsf256_mask",
+    "llvm.x86.avx512.mask.expand.load.ps.512" => "__builtin_ia32_expandloadsf512_mask",
+    "llvm.x86.avx512.mask.expand.load.q.128" => "__builtin_ia32_expandloaddi128_mask",
+    "llvm.x86.avx512.mask.expand.load.q.256" => "__builtin_ia32_expandloaddi256_mask",
+    "llvm.x86.avx512.mask.expand.load.q.512" => "__builtin_ia32_expandloaddi512_mask",
+    "llvm.x86.avx512.mask.expand.pd.128" => "__builtin_ia32_expanddf128_mask",
+    "llvm.x86.avx512.mask.expand.pd.256" => "__builtin_ia32_expanddf256_mask",
+    "llvm.x86.avx512.mask.expand.pd.512" => "__builtin_ia32_expanddf512_mask",
+    "llvm.x86.avx512.mask.expand.ps.128" => "__builtin_ia32_expandsf128_mask",
+    "llvm.x86.avx512.mask.expand.ps.256" => "__builtin_ia32_expandsf256_mask",
+    "llvm.x86.avx512.mask.expand.ps.512" => "__builtin_ia32_expandsf512_mask",
+    "llvm.x86.avx512.mask.expand.q.128" => "__builtin_ia32_expanddi128_mask",
+    "llvm.x86.avx512.mask.expand.q.256" => "__builtin_ia32_expanddi256_mask",
+    "llvm.x86.avx512.mask.expand.q.512" => "__builtin_ia32_expanddi512_mask",
+    "llvm.x86.avx512.mask.fixupimm.pd.128" => "__builtin_ia32_fixupimmpd128_mask",
+    "llvm.x86.avx512.mask.fixupimm.pd.256" => "__builtin_ia32_fixupimmpd256_mask",
+    "llvm.x86.avx512.mask.fixupimm.pd.512" => "__builtin_ia32_fixupimmpd512_mask",
+    "llvm.x86.avx512.mask.fixupimm.ps.128" => "__builtin_ia32_fixupimmps128_mask",
+    "llvm.x86.avx512.mask.fixupimm.ps.256" => "__builtin_ia32_fixupimmps256_mask",
+    "llvm.x86.avx512.mask.fixupimm.ps.512" => "__builtin_ia32_fixupimmps512_mask",
+    "llvm.x86.avx512.mask.fixupimm.sd" => "__builtin_ia32_fixupimmsd_mask",
+    "llvm.x86.avx512.mask.fixupimm.ss" => "__builtin_ia32_fixupimmss_mask",
+    "llvm.x86.avx512.mask.fpclass.pd.128" => "__builtin_ia32_fpclasspd128_mask",
+    "llvm.x86.avx512.mask.fpclass.pd.256" => "__builtin_ia32_fpclasspd256_mask",
+    "llvm.x86.avx512.mask.fpclass.pd.512" => "__builtin_ia32_fpclasspd512_mask",
+    "llvm.x86.avx512.mask.fpclass.ps.128" => "__builtin_ia32_fpclassps128_mask",
+    "llvm.x86.avx512.mask.fpclass.ps.256" => "__builtin_ia32_fpclassps256_mask",
+    "llvm.x86.avx512.mask.fpclass.ps.512" => "__builtin_ia32_fpclassps512_mask",
+    "llvm.x86.avx512.mask.fpclass.sd" => "__builtin_ia32_fpclasssd_mask",
+    "llvm.x86.avx512.mask.fpclass.ss" => "__builtin_ia32_fpclassss_mask",
+    "llvm.x86.avx512.mask.getexp.pd.128" => "__builtin_ia32_getexppd128_mask",
+    "llvm.x86.avx512.mask.getexp.pd.256" => "__builtin_ia32_getexppd256_mask",
+    "llvm.x86.avx512.mask.getexp.pd.512" => "__builtin_ia32_getexppd512_mask",
+    "llvm.x86.avx512.mask.getexp.ps.128" => "__builtin_ia32_getexpps128_mask",
+    "llvm.x86.avx512.mask.getexp.ps.256" => "__builtin_ia32_getexpps256_mask",
+    "llvm.x86.avx512.mask.getexp.ps.512" => "__builtin_ia32_getexpps512_mask",
+    "llvm.x86.avx512.mask.getexp.sd" => "__builtin_ia32_getexpsd128_round_mask",
+    "llvm.x86.avx512.mask.getexp.ss" => "__builtin_ia32_getexpss128_round_mask",
+    "llvm.x86.avx512.mask.getmant.pd.128" => "__builtin_ia32_getmantpd128_mask",
+    "llvm.x86.avx512.mask.getmant.pd.256" => "__builtin_ia32_getmantpd256_mask",
+    "llvm.x86.avx512.mask.getmant.pd.512" => "__builtin_ia32_getmantpd512_mask",
+    "llvm.x86.avx512.mask.getmant.ps.128" => "__builtin_ia32_getmantps128_mask",
+    "llvm.x86.avx512.mask.getmant.ps.256" => "__builtin_ia32_getmantps256_mask",
+    "llvm.x86.avx512.mask.getmant.ps.512" => "__builtin_ia32_getmantps512_mask",
+    "llvm.x86.avx512.mask.getmant.sd" => "__builtin_ia32_getmantsd_round_mask",
+    "llvm.x86.avx512.mask.getmant.ss" => "__builtin_ia32_getmantss_round_mask",
+    "llvm.x86.avx512.mask.insertf32x4.256" => "__builtin_ia32_insertf32x4_256_mask",
+    "llvm.x86.avx512.mask.insertf32x4.512" => "__builtin_ia32_insertf32x4_mask",
+    "llvm.x86.avx512.mask.insertf32x8.512" => "__builtin_ia32_insertf32x8_mask",
+    "llvm.x86.avx512.mask.insertf64x2.256" => "__builtin_ia32_insertf64x2_256_mask",
+    "llvm.x86.avx512.mask.insertf64x2.512" => "__builtin_ia32_insertf64x2_512_mask",
+    "llvm.x86.avx512.mask.insertf64x4.512" => "__builtin_ia32_insertf64x4_mask",
+    "llvm.x86.avx512.mask.inserti32x4.256" => "__builtin_ia32_inserti32x4_256_mask",
+    "llvm.x86.avx512.mask.inserti32x4.512" => "__builtin_ia32_inserti32x4_mask",
+    "llvm.x86.avx512.mask.inserti32x8.512" => "__builtin_ia32_inserti32x8_mask",
+    "llvm.x86.avx512.mask.inserti64x2.256" => "__builtin_ia32_inserti64x2_256_mask",
+    "llvm.x86.avx512.mask.inserti64x2.512" => "__builtin_ia32_inserti64x2_512_mask",
+    "llvm.x86.avx512.mask.inserti64x4.512" => "__builtin_ia32_inserti64x4_mask",
+    "llvm.x86.avx512.mask.loadu.d.512" => "__builtin_ia32_loaddqusi512_mask",
+    "llvm.x86.avx512.mask.loadu.pd.512" => "__builtin_ia32_loadupd512_mask",
+    "llvm.x86.avx512.mask.loadu.ps.512" => "__builtin_ia32_loadups512_mask",
+    "llvm.x86.avx512.mask.loadu.q.512" => "__builtin_ia32_loaddqudi512_mask",
+    "llvm.x86.avx512.mask.lzcnt.d.512" => "__builtin_ia32_vplzcntd_512_mask",
+    "llvm.x86.avx512.mask.lzcnt.q.512" => "__builtin_ia32_vplzcntq_512_mask",
+    "llvm.x86.avx512.mask.max.pd.128" => "__builtin_ia32_maxpd_mask",
+    "llvm.x86.avx512.mask.max.pd.256" => "__builtin_ia32_maxpd256_mask",
+    "llvm.x86.avx512.mask.max.pd.512" => "__builtin_ia32_maxpd512_mask",
+    "llvm.x86.avx512.mask.max.ps.128" => "__builtin_ia32_maxps_mask",
+    "llvm.x86.avx512.mask.max.ps.256" => "__builtin_ia32_maxps256_mask",
+    "llvm.x86.avx512.mask.max.ps.512" => "__builtin_ia32_maxps512_mask",
+    "llvm.x86.avx512.mask.max.sd.round" => "__builtin_ia32_maxsd_round_mask",
+    "llvm.x86.avx512.mask.max.ss.round" => "__builtin_ia32_maxss_round_mask",
+    "llvm.x86.avx512.mask.min.pd.128" => "__builtin_ia32_minpd_mask",
+    "llvm.x86.avx512.mask.min.pd.256" => "__builtin_ia32_minpd256_mask",
+    "llvm.x86.avx512.mask.min.pd.512" => "__builtin_ia32_minpd512_mask",
+    "llvm.x86.avx512.mask.min.ps.128" => "__builtin_ia32_minps_mask",
+    "llvm.x86.avx512.mask.min.ps.256" => "__builtin_ia32_minps256_mask",
+    "llvm.x86.avx512.mask.min.ps.512" => "__builtin_ia32_minps512_mask",
+    "llvm.x86.avx512.mask.min.sd.round" => "__builtin_ia32_minsd_round_mask",
+    "llvm.x86.avx512.mask.min.ss.round" => "__builtin_ia32_minss_round_mask",
+    "llvm.x86.avx512.mask.move.sd" => "__builtin_ia32_movsd_mask",
+    "llvm.x86.avx512.mask.move.ss" => "__builtin_ia32_movss_mask",
+    "llvm.x86.avx512.mask.mul.pd.128" => "__builtin_ia32_mulpd_mask",
+    "llvm.x86.avx512.mask.mul.pd.256" => "__builtin_ia32_mulpd256_mask",
+    "llvm.x86.avx512.mask.mul.pd.512" => "__builtin_ia32_mulpd512_mask",
+    "llvm.x86.avx512.mask.mul.ps.128" => "__builtin_ia32_mulps_mask",
+    "llvm.x86.avx512.mask.mul.ps.256" => "__builtin_ia32_mulps256_mask",
+    "llvm.x86.avx512.mask.mul.ps.512" => "__builtin_ia32_mulps512_mask",
+    "llvm.x86.avx512.mask.mul.sd.round" => "__builtin_ia32_mulsd_round_mask",
+    "llvm.x86.avx512.mask.mul.ss.round" => "__builtin_ia32_mulss_round_mask",
+    "llvm.x86.avx512.mask.or.pd.128" => "__builtin_ia32_orpd128_mask",
+    "llvm.x86.avx512.mask.or.pd.256" => "__builtin_ia32_orpd256_mask",
+    "llvm.x86.avx512.mask.or.pd.512" => "__builtin_ia32_orpd512_mask",
+    "llvm.x86.avx512.mask.or.ps.128" => "__builtin_ia32_orps128_mask",
+    "llvm.x86.avx512.mask.or.ps.256" => "__builtin_ia32_orps256_mask",
+    "llvm.x86.avx512.mask.or.ps.512" => "__builtin_ia32_orps512_mask",
+    "llvm.x86.avx512.mask.pabs.b.128" => "__builtin_ia32_pabsb128_mask",
+    "llvm.x86.avx512.mask.pabs.b.256" => "__builtin_ia32_pabsb256_mask",
+    "llvm.x86.avx512.mask.pabs.b.512" => "__builtin_ia32_pabsb512_mask",
+    "llvm.x86.avx512.mask.pabs.d.128" => "__builtin_ia32_pabsd128_mask",
+    "llvm.x86.avx512.mask.pabs.d.256" => "__builtin_ia32_pabsd256_mask",
+    "llvm.x86.avx512.mask.pabs.d.512" => "__builtin_ia32_pabsd512_mask",
+    "llvm.x86.avx512.mask.pabs.q.128" => "__builtin_ia32_pabsq128_mask",
+    "llvm.x86.avx512.mask.pabs.q.256" => "__builtin_ia32_pabsq256_mask",
+    "llvm.x86.avx512.mask.pabs.q.512" => "__builtin_ia32_pabsq512_mask",
+    "llvm.x86.avx512.mask.pabs.w.128" => "__builtin_ia32_pabsw128_mask",
+    "llvm.x86.avx512.mask.pabs.w.256" => "__builtin_ia32_pabsw256_mask",
+    "llvm.x86.avx512.mask.pabs.w.512" => "__builtin_ia32_pabsw512_mask",
+    "llvm.x86.avx512.mask.packssdw.128" => "__builtin_ia32_packssdw128_mask",
+    "llvm.x86.avx512.mask.packssdw.256" => "__builtin_ia32_packssdw256_mask",
+    "llvm.x86.avx512.mask.packssdw.512" => "__builtin_ia32_packssdw512_mask",
+    "llvm.x86.avx512.mask.packsswb.128" => "__builtin_ia32_packsswb128_mask",
+    "llvm.x86.avx512.mask.packsswb.256" => "__builtin_ia32_packsswb256_mask",
+    "llvm.x86.avx512.mask.packsswb.512" => "__builtin_ia32_packsswb512_mask",
+    "llvm.x86.avx512.mask.packusdw.128" => "__builtin_ia32_packusdw128_mask",
+    "llvm.x86.avx512.mask.packusdw.256" => "__builtin_ia32_packusdw256_mask",
+    "llvm.x86.avx512.mask.packusdw.512" => "__builtin_ia32_packusdw512_mask",
+    "llvm.x86.avx512.mask.packuswb.128" => "__builtin_ia32_packuswb128_mask",
+    "llvm.x86.avx512.mask.packuswb.256" => "__builtin_ia32_packuswb256_mask",
+    "llvm.x86.avx512.mask.packuswb.512" => "__builtin_ia32_packuswb512_mask",
+    "llvm.x86.avx512.mask.padd.b.128" => "__builtin_ia32_paddb128_mask",
+    "llvm.x86.avx512.mask.padd.b.256" => "__builtin_ia32_paddb256_mask",
+    "llvm.x86.avx512.mask.padd.b.512" => "__builtin_ia32_paddb512_mask",
+    "llvm.x86.avx512.mask.padd.d.128" => "__builtin_ia32_paddd128_mask",
+    "llvm.x86.avx512.mask.padd.d.256" => "__builtin_ia32_paddd256_mask",
+    "llvm.x86.avx512.mask.padd.d.512" => "__builtin_ia32_paddd512_mask",
+    "llvm.x86.avx512.mask.padd.q.128" => "__builtin_ia32_paddq128_mask",
+    "llvm.x86.avx512.mask.padd.q.256" => "__builtin_ia32_paddq256_mask",
+    "llvm.x86.avx512.mask.padd.q.512" => "__builtin_ia32_paddq512_mask",
+    "llvm.x86.avx512.mask.padd.w.128" => "__builtin_ia32_paddw128_mask",
+    "llvm.x86.avx512.mask.padd.w.256" => "__builtin_ia32_paddw256_mask",
+    "llvm.x86.avx512.mask.padd.w.512" => "__builtin_ia32_paddw512_mask",
+    "llvm.x86.avx512.mask.padds.b.128" => "__builtin_ia32_paddsb128_mask",
+    "llvm.x86.avx512.mask.padds.b.256" => "__builtin_ia32_paddsb256_mask",
+    "llvm.x86.avx512.mask.padds.b.512" => "__builtin_ia32_paddsb512_mask",
+    "llvm.x86.avx512.mask.padds.w.128" => "__builtin_ia32_paddsw128_mask",
+    "llvm.x86.avx512.mask.padds.w.256" => "__builtin_ia32_paddsw256_mask",
+    "llvm.x86.avx512.mask.padds.w.512" => "__builtin_ia32_paddsw512_mask",
+    "llvm.x86.avx512.mask.paddus.b.128" => "__builtin_ia32_paddusb128_mask",
+    "llvm.x86.avx512.mask.paddus.b.256" => "__builtin_ia32_paddusb256_mask",
+    "llvm.x86.avx512.mask.paddus.b.512" => "__builtin_ia32_paddusb512_mask",
+    "llvm.x86.avx512.mask.paddus.w.128" => "__builtin_ia32_paddusw128_mask",
+    "llvm.x86.avx512.mask.paddus.w.256" => "__builtin_ia32_paddusw256_mask",
+    "llvm.x86.avx512.mask.paddus.w.512" => "__builtin_ia32_paddusw512_mask",
+    "llvm.x86.avx512.mask.pand.d.512" => "__builtin_ia32_pandd512_mask",
+    "llvm.x86.avx512.mask.pand.q.512" => "__builtin_ia32_pandq512_mask",
+    "llvm.x86.avx512.mask.pavg.b.128" => "__builtin_ia32_pavgb128_mask",
+    "llvm.x86.avx512.mask.pavg.b.256" => "__builtin_ia32_pavgb256_mask",
+    "llvm.x86.avx512.mask.pavg.b.512" => "__builtin_ia32_pavgb512_mask",
+    "llvm.x86.avx512.mask.pavg.w.128" => "__builtin_ia32_pavgw128_mask",
+    "llvm.x86.avx512.mask.pavg.w.256" => "__builtin_ia32_pavgw256_mask",
+    "llvm.x86.avx512.mask.pavg.w.512" => "__builtin_ia32_pavgw512_mask",
+    "llvm.x86.avx512.mask.pbroadcast.b.gpr.128" => "__builtin_ia32_pbroadcastb128_gpr_mask",
+    "llvm.x86.avx512.mask.pbroadcast.b.gpr.256" => "__builtin_ia32_pbroadcastb256_gpr_mask",
+    "llvm.x86.avx512.mask.pbroadcast.b.gpr.512" => "__builtin_ia32_pbroadcastb512_gpr_mask",
+    "llvm.x86.avx512.mask.pbroadcast.d.gpr.128" => "__builtin_ia32_pbroadcastd128_gpr_mask",
+    "llvm.x86.avx512.mask.pbroadcast.d.gpr.256" => "__builtin_ia32_pbroadcastd256_gpr_mask",
+    "llvm.x86.avx512.mask.pbroadcast.d.gpr.512" => "__builtin_ia32_pbroadcastd512_gpr_mask",
+    "llvm.x86.avx512.mask.pbroadcast.q.gpr.128" => "__builtin_ia32_pbroadcastq128_gpr_mask",
+    "llvm.x86.avx512.mask.pbroadcast.q.gpr.256" => "__builtin_ia32_pbroadcastq256_gpr_mask",
+    "llvm.x86.avx512.mask.pbroadcast.q.gpr.512" => "__builtin_ia32_pbroadcastq512_gpr_mask",
+    "llvm.x86.avx512.mask.pbroadcast.q.mem.512" => "__builtin_ia32_pbroadcastq512_mem_mask",
+    "llvm.x86.avx512.mask.pbroadcast.w.gpr.128" => "__builtin_ia32_pbroadcastw128_gpr_mask",
+    "llvm.x86.avx512.mask.pbroadcast.w.gpr.256" => "__builtin_ia32_pbroadcastw256_gpr_mask",
+    "llvm.x86.avx512.mask.pbroadcast.w.gpr.512" => "__builtin_ia32_pbroadcastw512_gpr_mask",
+    "llvm.x86.avx512.mask.pcmpeq.b.128" => "__builtin_ia32_pcmpeqb128_mask",
+    "llvm.x86.avx512.mask.pcmpeq.b.256" => "__builtin_ia32_pcmpeqb256_mask",
+    "llvm.x86.avx512.mask.pcmpeq.b.512" => "__builtin_ia32_pcmpeqb512_mask",
+    "llvm.x86.avx512.mask.pcmpeq.d.128" => "__builtin_ia32_pcmpeqd128_mask",
+    "llvm.x86.avx512.mask.pcmpeq.d.256" => "__builtin_ia32_pcmpeqd256_mask",
+    "llvm.x86.avx512.mask.pcmpeq.d.512" => "__builtin_ia32_pcmpeqd512_mask",
+    "llvm.x86.avx512.mask.pcmpeq.q.128" => "__builtin_ia32_pcmpeqq128_mask",
+    "llvm.x86.avx512.mask.pcmpeq.q.256" => "__builtin_ia32_pcmpeqq256_mask",
+    "llvm.x86.avx512.mask.pcmpeq.q.512" => "__builtin_ia32_pcmpeqq512_mask",
+    "llvm.x86.avx512.mask.pcmpeq.w.128" => "__builtin_ia32_pcmpeqw128_mask",
+    "llvm.x86.avx512.mask.pcmpeq.w.256" => "__builtin_ia32_pcmpeqw256_mask",
+    "llvm.x86.avx512.mask.pcmpeq.w.512" => "__builtin_ia32_pcmpeqw512_mask",
+    "llvm.x86.avx512.mask.pcmpgt.b.128" => "__builtin_ia32_pcmpgtb128_mask",
+    "llvm.x86.avx512.mask.pcmpgt.b.256" => "__builtin_ia32_pcmpgtb256_mask",
+    "llvm.x86.avx512.mask.pcmpgt.b.512" => "__builtin_ia32_pcmpgtb512_mask",
+    "llvm.x86.avx512.mask.pcmpgt.d.128" => "__builtin_ia32_pcmpgtd128_mask",
+    "llvm.x86.avx512.mask.pcmpgt.d.256" => "__builtin_ia32_pcmpgtd256_mask",
+    "llvm.x86.avx512.mask.pcmpgt.d.512" => "__builtin_ia32_pcmpgtd512_mask",
+    "llvm.x86.avx512.mask.pcmpgt.q.128" => "__builtin_ia32_pcmpgtq128_mask",
+    "llvm.x86.avx512.mask.pcmpgt.q.256" => "__builtin_ia32_pcmpgtq256_mask",
+    "llvm.x86.avx512.mask.pcmpgt.q.512" => "__builtin_ia32_pcmpgtq512_mask",
+    "llvm.x86.avx512.mask.pcmpgt.w.128" => "__builtin_ia32_pcmpgtw128_mask",
+    "llvm.x86.avx512.mask.pcmpgt.w.256" => "__builtin_ia32_pcmpgtw256_mask",
+    "llvm.x86.avx512.mask.pcmpgt.w.512" => "__builtin_ia32_pcmpgtw512_mask",
+    "llvm.x86.avx512.mask.permvar.df.256" => "__builtin_ia32_permvardf256_mask",
+    "llvm.x86.avx512.mask.permvar.df.512" => "__builtin_ia32_permvardf512_mask",
+    "llvm.x86.avx512.mask.permvar.di.256" => "__builtin_ia32_permvardi256_mask",
+    "llvm.x86.avx512.mask.permvar.di.512" => "__builtin_ia32_permvardi512_mask",
+    "llvm.x86.avx512.mask.permvar.hi.128" => "__builtin_ia32_permvarhi128_mask",
+    "llvm.x86.avx512.mask.permvar.hi.256" => "__builtin_ia32_permvarhi256_mask",
+    "llvm.x86.avx512.mask.permvar.hi.512" => "__builtin_ia32_permvarhi512_mask",
+    "llvm.x86.avx512.mask.permvar.qi.128" => "__builtin_ia32_permvarqi128_mask",
+    "llvm.x86.avx512.mask.permvar.qi.256" => "__builtin_ia32_permvarqi256_mask",
+    "llvm.x86.avx512.mask.permvar.qi.512" => "__builtin_ia32_permvarqi512_mask",
+    "llvm.x86.avx512.mask.permvar.sf.256" => "__builtin_ia32_permvarsf256_mask",
+    "llvm.x86.avx512.mask.permvar.sf.512" => "__builtin_ia32_permvarsf512_mask",
+    "llvm.x86.avx512.mask.permvar.si.256" => "__builtin_ia32_permvarsi256_mask",
+    "llvm.x86.avx512.mask.permvar.si.512" => "__builtin_ia32_permvarsi512_mask",
+    "llvm.x86.avx512.mask.pmaddubs.w.128" => "__builtin_ia32_pmaddubsw128_mask",
+    "llvm.x86.avx512.mask.pmaddubs.w.256" => "__builtin_ia32_pmaddubsw256_mask",
+    "llvm.x86.avx512.mask.pmaddubs.w.512" => "__builtin_ia32_pmaddubsw512_mask",
+    "llvm.x86.avx512.mask.pmaddw.d.128" => "__builtin_ia32_pmaddwd128_mask",
+    "llvm.x86.avx512.mask.pmaddw.d.256" => "__builtin_ia32_pmaddwd256_mask",
+    "llvm.x86.avx512.mask.pmaddw.d.512" => "__builtin_ia32_pmaddwd512_mask",
+    "llvm.x86.avx512.mask.pmaxs.b.128" => "__builtin_ia32_pmaxsb128_mask",
+    "llvm.x86.avx512.mask.pmaxs.b.256" => "__builtin_ia32_pmaxsb256_mask",
+    "llvm.x86.avx512.mask.pmaxs.b.512" => "__builtin_ia32_pmaxsb512_mask",
+    "llvm.x86.avx512.mask.pmaxs.d.128" => "__builtin_ia32_pmaxsd128_mask",
+    "llvm.x86.avx512.mask.pmaxs.d.256" => "__builtin_ia32_pmaxsd256_mask",
+    "llvm.x86.avx512.mask.pmaxs.d.512" => "__builtin_ia32_pmaxsd512_mask",
+    "llvm.x86.avx512.mask.pmaxs.q.128" => "__builtin_ia32_pmaxsq128_mask",
+    "llvm.x86.avx512.mask.pmaxs.q.256" => "__builtin_ia32_pmaxsq256_mask",
+    "llvm.x86.avx512.mask.pmaxs.q.512" => "__builtin_ia32_pmaxsq512_mask",
+    "llvm.x86.avx512.mask.pmaxs.w.128" => "__builtin_ia32_pmaxsw128_mask",
+    "llvm.x86.avx512.mask.pmaxs.w.256" => "__builtin_ia32_pmaxsw256_mask",
+    "llvm.x86.avx512.mask.pmaxs.w.512" => "__builtin_ia32_pmaxsw512_mask",
+    "llvm.x86.avx512.mask.pmaxu.b.128" => "__builtin_ia32_pmaxub128_mask",
+    "llvm.x86.avx512.mask.pmaxu.b.256" => "__builtin_ia32_pmaxub256_mask",
+    "llvm.x86.avx512.mask.pmaxu.b.512" => "__builtin_ia32_pmaxub512_mask",
+    "llvm.x86.avx512.mask.pmaxu.d.128" => "__builtin_ia32_pmaxud128_mask",
+    "llvm.x86.avx512.mask.pmaxu.d.256" => "__builtin_ia32_pmaxud256_mask",
+    "llvm.x86.avx512.mask.pmaxu.d.512" => "__builtin_ia32_pmaxud512_mask",
+    "llvm.x86.avx512.mask.pmaxu.q.128" => "__builtin_ia32_pmaxuq128_mask",
+    "llvm.x86.avx512.mask.pmaxu.q.256" => "__builtin_ia32_pmaxuq256_mask",
+    "llvm.x86.avx512.mask.pmaxu.q.512" => "__builtin_ia32_pmaxuq512_mask",
+    "llvm.x86.avx512.mask.pmaxu.w.128" => "__builtin_ia32_pmaxuw128_mask",
+    "llvm.x86.avx512.mask.pmaxu.w.256" => "__builtin_ia32_pmaxuw256_mask",
+    "llvm.x86.avx512.mask.pmaxu.w.512" => "__builtin_ia32_pmaxuw512_mask",
+    "llvm.x86.avx512.mask.pmins.b.128" => "__builtin_ia32_pminsb128_mask",
+    "llvm.x86.avx512.mask.pmins.b.256" => "__builtin_ia32_pminsb256_mask",
+    "llvm.x86.avx512.mask.pmins.b.512" => "__builtin_ia32_pminsb512_mask",
+    "llvm.x86.avx512.mask.pmins.d.128" => "__builtin_ia32_pminsd128_mask",
+    "llvm.x86.avx512.mask.pmins.d.256" => "__builtin_ia32_pminsd256_mask",
+    "llvm.x86.avx512.mask.pmins.d.512" => "__builtin_ia32_pminsd512_mask",
+    "llvm.x86.avx512.mask.pmins.q.128" => "__builtin_ia32_pminsq128_mask",
+    "llvm.x86.avx512.mask.pmins.q.256" => "__builtin_ia32_pminsq256_mask",
+    "llvm.x86.avx512.mask.pmins.q.512" => "__builtin_ia32_pminsq512_mask",
+    "llvm.x86.avx512.mask.pmins.w.128" => "__builtin_ia32_pminsw128_mask",
+    "llvm.x86.avx512.mask.pmins.w.256" => "__builtin_ia32_pminsw256_mask",
+    "llvm.x86.avx512.mask.pmins.w.512" => "__builtin_ia32_pminsw512_mask",
+    "llvm.x86.avx512.mask.pminu.b.128" => "__builtin_ia32_pminub128_mask",
+    "llvm.x86.avx512.mask.pminu.b.256" => "__builtin_ia32_pminub256_mask",
+    "llvm.x86.avx512.mask.pminu.b.512" => "__builtin_ia32_pminub512_mask",
+    "llvm.x86.avx512.mask.pminu.d.128" => "__builtin_ia32_pminud128_mask",
+    "llvm.x86.avx512.mask.pminu.d.256" => "__builtin_ia32_pminud256_mask",
+    "llvm.x86.avx512.mask.pminu.d.512" => "__builtin_ia32_pminud512_mask",
+    "llvm.x86.avx512.mask.pminu.q.128" => "__builtin_ia32_pminuq128_mask",
+    "llvm.x86.avx512.mask.pminu.q.256" => "__builtin_ia32_pminuq256_mask",
+    "llvm.x86.avx512.mask.pminu.q.512" => "__builtin_ia32_pminuq512_mask",
+    "llvm.x86.avx512.mask.pminu.w.128" => "__builtin_ia32_pminuw128_mask",
+    "llvm.x86.avx512.mask.pminu.w.256" => "__builtin_ia32_pminuw256_mask",
+    "llvm.x86.avx512.mask.pminu.w.512" => "__builtin_ia32_pminuw512_mask",
+    "llvm.x86.avx512.mask.pmov.db.128" => "__builtin_ia32_pmovdb128_mask",
+    "llvm.x86.avx512.mask.pmov.db.256" => "__builtin_ia32_pmovdb256_mask",
+    "llvm.x86.avx512.mask.pmov.db.512" => "__builtin_ia32_pmovdb512_mask",
+    "llvm.x86.avx512.mask.pmov.db.mem.128" => "__builtin_ia32_pmovdb128mem_mask",
+    "llvm.x86.avx512.mask.pmov.db.mem.256" => "__builtin_ia32_pmovdb256mem_mask",
+    "llvm.x86.avx512.mask.pmov.db.mem.512" => "__builtin_ia32_pmovdb512mem_mask",
+    "llvm.x86.avx512.mask.pmov.dw.128" => "__builtin_ia32_pmovdw128_mask",
+    "llvm.x86.avx512.mask.pmov.dw.256" => "__builtin_ia32_pmovdw256_mask",
+    "llvm.x86.avx512.mask.pmov.dw.512" => "__builtin_ia32_pmovdw512_mask",
+    "llvm.x86.avx512.mask.pmov.dw.mem.128" => "__builtin_ia32_pmovdw128mem_mask",
+    "llvm.x86.avx512.mask.pmov.dw.mem.256" => "__builtin_ia32_pmovdw256mem_mask",
+    "llvm.x86.avx512.mask.pmov.dw.mem.512" => "__builtin_ia32_pmovdw512mem_mask",
+    "llvm.x86.avx512.mask.pmov.qb.128" => "__builtin_ia32_pmovqb128_mask",
+    "llvm.x86.avx512.mask.pmov.qb.256" => "__builtin_ia32_pmovqb256_mask",
+    "llvm.x86.avx512.mask.pmov.qb.512" => "__builtin_ia32_pmovqb512_mask",
+    "llvm.x86.avx512.mask.pmov.qb.mem.128" => "__builtin_ia32_pmovqb128mem_mask",
+    "llvm.x86.avx512.mask.pmov.qb.mem.256" => "__builtin_ia32_pmovqb256mem_mask",
+    "llvm.x86.avx512.mask.pmov.qb.mem.512" => "__builtin_ia32_pmovqb512mem_mask",
+    "llvm.x86.avx512.mask.pmov.qd.128" => "__builtin_ia32_pmovqd128_mask",
+    "llvm.x86.avx512.mask.pmov.qd.256" => "__builtin_ia32_pmovqd256_mask",
+    "llvm.x86.avx512.mask.pmov.qd.512" => "__builtin_ia32_pmovqd512_mask",
+    "llvm.x86.avx512.mask.pmov.qd.mem.128" => "__builtin_ia32_pmovqd128mem_mask",
+    "llvm.x86.avx512.mask.pmov.qd.mem.256" => "__builtin_ia32_pmovqd256mem_mask",
+    "llvm.x86.avx512.mask.pmov.qd.mem.512" => "__builtin_ia32_pmovqd512mem_mask",
+    "llvm.x86.avx512.mask.pmov.qw.128" => "__builtin_ia32_pmovqw128_mask",
+    "llvm.x86.avx512.mask.pmov.qw.256" => "__builtin_ia32_pmovqw256_mask",
+    "llvm.x86.avx512.mask.pmov.qw.512" => "__builtin_ia32_pmovqw512_mask",
+    "llvm.x86.avx512.mask.pmov.qw.mem.128" => "__builtin_ia32_pmovqw128mem_mask",
+    "llvm.x86.avx512.mask.pmov.qw.mem.256" => "__builtin_ia32_pmovqw256mem_mask",
+    "llvm.x86.avx512.mask.pmov.qw.mem.512" => "__builtin_ia32_pmovqw512mem_mask",
+    "llvm.x86.avx512.mask.pmov.wb.128" => "__builtin_ia32_pmovwb128_mask",
+    "llvm.x86.avx512.mask.pmov.wb.256" => "__builtin_ia32_pmovwb256_mask",
+    "llvm.x86.avx512.mask.pmov.wb.512" => "__builtin_ia32_pmovwb512_mask",
+    "llvm.x86.avx512.mask.pmov.wb.mem.128" => "__builtin_ia32_pmovwb128mem_mask",
+    "llvm.x86.avx512.mask.pmov.wb.mem.256" => "__builtin_ia32_pmovwb256mem_mask",
+    "llvm.x86.avx512.mask.pmov.wb.mem.512" => "__builtin_ia32_pmovwb512mem_mask",
+    "llvm.x86.avx512.mask.pmovs.db.128" => "__builtin_ia32_pmovsdb128_mask",
+    "llvm.x86.avx512.mask.pmovs.db.256" => "__builtin_ia32_pmovsdb256_mask",
+    "llvm.x86.avx512.mask.pmovs.db.512" => "__builtin_ia32_pmovsdb512_mask",
+    "llvm.x86.avx512.mask.pmovs.db.mem.128" => "__builtin_ia32_pmovsdb128mem_mask",
+    "llvm.x86.avx512.mask.pmovs.db.mem.256" => "__builtin_ia32_pmovsdb256mem_mask",
+    "llvm.x86.avx512.mask.pmovs.db.mem.512" => "__builtin_ia32_pmovsdb512mem_mask",
+    "llvm.x86.avx512.mask.pmovs.dw.128" => "__builtin_ia32_pmovsdw128_mask",
+    "llvm.x86.avx512.mask.pmovs.dw.256" => "__builtin_ia32_pmovsdw256_mask",
+    "llvm.x86.avx512.mask.pmovs.dw.512" => "__builtin_ia32_pmovsdw512_mask",
+    "llvm.x86.avx512.mask.pmovs.dw.mem.128" => "__builtin_ia32_pmovsdw128mem_mask",
+    "llvm.x86.avx512.mask.pmovs.dw.mem.256" => "__builtin_ia32_pmovsdw256mem_mask",
+    "llvm.x86.avx512.mask.pmovs.dw.mem.512" => "__builtin_ia32_pmovsdw512mem_mask",
+    "llvm.x86.avx512.mask.pmovs.qb.128" => "__builtin_ia32_pmovsqb128_mask",
+    "llvm.x86.avx512.mask.pmovs.qb.256" => "__builtin_ia32_pmovsqb256_mask",
+    "llvm.x86.avx512.mask.pmovs.qb.512" => "__builtin_ia32_pmovsqb512_mask",
+    "llvm.x86.avx512.mask.pmovs.qb.mem.128" => "__builtin_ia32_pmovsqb128mem_mask",
+    "llvm.x86.avx512.mask.pmovs.qb.mem.256" => "__builtin_ia32_pmovsqb256mem_mask",
+    "llvm.x86.avx512.mask.pmovs.qb.mem.512" => "__builtin_ia32_pmovsqb512mem_mask",
+    "llvm.x86.avx512.mask.pmovs.qd.128" => "__builtin_ia32_pmovsqd128_mask",
+    "llvm.x86.avx512.mask.pmovs.qd.256" => "__builtin_ia32_pmovsqd256_mask",
+    "llvm.x86.avx512.mask.pmovs.qd.512" => "__builtin_ia32_pmovsqd512_mask",
+    "llvm.x86.avx512.mask.pmovs.qd.mem.128" => "__builtin_ia32_pmovsqd128mem_mask",
+    "llvm.x86.avx512.mask.pmovs.qd.mem.256" => "__builtin_ia32_pmovsqd256mem_mask",
+    "llvm.x86.avx512.mask.pmovs.qd.mem.512" => "__builtin_ia32_pmovsqd512mem_mask",
+    "llvm.x86.avx512.mask.pmovs.qw.128" => "__builtin_ia32_pmovsqw128_mask",
+    "llvm.x86.avx512.mask.pmovs.qw.256" => "__builtin_ia32_pmovsqw256_mask",
+    "llvm.x86.avx512.mask.pmovs.qw.512" => "__builtin_ia32_pmovsqw512_mask",
+    "llvm.x86.avx512.mask.pmovs.qw.mem.128" => "__builtin_ia32_pmovsqw128mem_mask",
+    "llvm.x86.avx512.mask.pmovs.qw.mem.256" => "__builtin_ia32_pmovsqw256mem_mask",
+    "llvm.x86.avx512.mask.pmovs.qw.mem.512" => "__builtin_ia32_pmovsqw512mem_mask",
+    "llvm.x86.avx512.mask.pmovs.wb.128" => "__builtin_ia32_pmovswb128_mask",
+    "llvm.x86.avx512.mask.pmovs.wb.256" => "__builtin_ia32_pmovswb256_mask",
+    "llvm.x86.avx512.mask.pmovs.wb.512" => "__builtin_ia32_pmovswb512_mask",
+    "llvm.x86.avx512.mask.pmovs.wb.mem.128" => "__builtin_ia32_pmovswb128mem_mask",
+    "llvm.x86.avx512.mask.pmovs.wb.mem.256" => "__builtin_ia32_pmovswb256mem_mask",
+    "llvm.x86.avx512.mask.pmovs.wb.mem.512" => "__builtin_ia32_pmovswb512mem_mask",
+    "llvm.x86.avx512.mask.pmovsxb.d.128" => "__builtin_ia32_pmovsxbd128_mask",
+    "llvm.x86.avx512.mask.pmovsxb.d.256" => "__builtin_ia32_pmovsxbd256_mask",
+    "llvm.x86.avx512.mask.pmovsxb.d.512" => "__builtin_ia32_pmovsxbd512_mask",
+    "llvm.x86.avx512.mask.pmovsxb.q.128" => "__builtin_ia32_pmovsxbq128_mask",
+    "llvm.x86.avx512.mask.pmovsxb.q.256" => "__builtin_ia32_pmovsxbq256_mask",
+    "llvm.x86.avx512.mask.pmovsxb.q.512" => "__builtin_ia32_pmovsxbq512_mask",
+    "llvm.x86.avx512.mask.pmovsxb.w.128" => "__builtin_ia32_pmovsxbw128_mask",
+    "llvm.x86.avx512.mask.pmovsxb.w.256" => "__builtin_ia32_pmovsxbw256_mask",
+    "llvm.x86.avx512.mask.pmovsxb.w.512" => "__builtin_ia32_pmovsxbw512_mask",
+    "llvm.x86.avx512.mask.pmovsxd.q.128" => "__builtin_ia32_pmovsxdq128_mask",
+    "llvm.x86.avx512.mask.pmovsxd.q.256" => "__builtin_ia32_pmovsxdq256_mask",
+    "llvm.x86.avx512.mask.pmovsxd.q.512" => "__builtin_ia32_pmovsxdq512_mask",
+    "llvm.x86.avx512.mask.pmovsxw.d.128" => "__builtin_ia32_pmovsxwd128_mask",
+    "llvm.x86.avx512.mask.pmovsxw.d.256" => "__builtin_ia32_pmovsxwd256_mask",
+    "llvm.x86.avx512.mask.pmovsxw.d.512" => "__builtin_ia32_pmovsxwd512_mask",
+    "llvm.x86.avx512.mask.pmovsxw.q.128" => "__builtin_ia32_pmovsxwq128_mask",
+    "llvm.x86.avx512.mask.pmovsxw.q.256" => "__builtin_ia32_pmovsxwq256_mask",
+    "llvm.x86.avx512.mask.pmovsxw.q.512" => "__builtin_ia32_pmovsxwq512_mask",
+    "llvm.x86.avx512.mask.pmovus.db.128" => "__builtin_ia32_pmovusdb128_mask",
+    "llvm.x86.avx512.mask.pmovus.db.256" => "__builtin_ia32_pmovusdb256_mask",
+    "llvm.x86.avx512.mask.pmovus.db.512" => "__builtin_ia32_pmovusdb512_mask",
+    "llvm.x86.avx512.mask.pmovus.db.mem.128" => "__builtin_ia32_pmovusdb128mem_mask",
+    "llvm.x86.avx512.mask.pmovus.db.mem.256" => "__builtin_ia32_pmovusdb256mem_mask",
+    "llvm.x86.avx512.mask.pmovus.db.mem.512" => "__builtin_ia32_pmovusdb512mem_mask",
+    "llvm.x86.avx512.mask.pmovus.dw.128" => "__builtin_ia32_pmovusdw128_mask",
+    "llvm.x86.avx512.mask.pmovus.dw.256" => "__builtin_ia32_pmovusdw256_mask",
+    "llvm.x86.avx512.mask.pmovus.dw.512" => "__builtin_ia32_pmovusdw512_mask",
+    "llvm.x86.avx512.mask.pmovus.dw.mem.128" => "__builtin_ia32_pmovusdw128mem_mask",
+    "llvm.x86.avx512.mask.pmovus.dw.mem.256" => "__builtin_ia32_pmovusdw256mem_mask",
+    "llvm.x86.avx512.mask.pmovus.dw.mem.512" => "__builtin_ia32_pmovusdw512mem_mask",
+    "llvm.x86.avx512.mask.pmovus.qb.128" => "__builtin_ia32_pmovusqb128_mask",
+    "llvm.x86.avx512.mask.pmovus.qb.256" => "__builtin_ia32_pmovusqb256_mask",
+    "llvm.x86.avx512.mask.pmovus.qb.512" => "__builtin_ia32_pmovusqb512_mask",
+    "llvm.x86.avx512.mask.pmovus.qb.mem.128" => "__builtin_ia32_pmovusqb128mem_mask",
+    "llvm.x86.avx512.mask.pmovus.qb.mem.256" => "__builtin_ia32_pmovusqb256mem_mask",
+    "llvm.x86.avx512.mask.pmovus.qb.mem.512" => "__builtin_ia32_pmovusqb512mem_mask",
+    "llvm.x86.avx512.mask.pmovus.qd.128" => "__builtin_ia32_pmovusqd128_mask",
+    "llvm.x86.avx512.mask.pmovus.qd.256" => "__builtin_ia32_pmovusqd256_mask",
+    "llvm.x86.avx512.mask.pmovus.qd.512" => "__builtin_ia32_pmovusqd512_mask",
+    "llvm.x86.avx512.mask.pmovus.qd.mem.128" => "__builtin_ia32_pmovusqd128mem_mask",
+    "llvm.x86.avx512.mask.pmovus.qd.mem.256" => "__builtin_ia32_pmovusqd256mem_mask",
+    "llvm.x86.avx512.mask.pmovus.qd.mem.512" => "__builtin_ia32_pmovusqd512mem_mask",
+    "llvm.x86.avx512.mask.pmovus.qw.128" => "__builtin_ia32_pmovusqw128_mask",
+    "llvm.x86.avx512.mask.pmovus.qw.256" => "__builtin_ia32_pmovusqw256_mask",
+    "llvm.x86.avx512.mask.pmovus.qw.512" => "__builtin_ia32_pmovusqw512_mask",
+    "llvm.x86.avx512.mask.pmovus.qw.mem.128" => "__builtin_ia32_pmovusqw128mem_mask",
+    "llvm.x86.avx512.mask.pmovus.qw.mem.256" => "__builtin_ia32_pmovusqw256mem_mask",
+    "llvm.x86.avx512.mask.pmovus.qw.mem.512" => "__builtin_ia32_pmovusqw512mem_mask",
+    "llvm.x86.avx512.mask.pmovus.wb.128" => "__builtin_ia32_pmovuswb128_mask",
+    "llvm.x86.avx512.mask.pmovus.wb.256" => "__builtin_ia32_pmovuswb256_mask",
+    "llvm.x86.avx512.mask.pmovus.wb.512" => "__builtin_ia32_pmovuswb512_mask",
+    "llvm.x86.avx512.mask.pmovus.wb.mem.128" => "__builtin_ia32_pmovuswb128mem_mask",
+    "llvm.x86.avx512.mask.pmovus.wb.mem.256" => "__builtin_ia32_pmovuswb256mem_mask",
+    "llvm.x86.avx512.mask.pmovus.wb.mem.512" => "__builtin_ia32_pmovuswb512mem_mask",
+    "llvm.x86.avx512.mask.pmovzxb.d.128" => "__builtin_ia32_pmovzxbd128_mask",
+    "llvm.x86.avx512.mask.pmovzxb.d.256" => "__builtin_ia32_pmovzxbd256_mask",
+    "llvm.x86.avx512.mask.pmovzxb.d.512" => "__builtin_ia32_pmovzxbd512_mask",
+    "llvm.x86.avx512.mask.pmovzxb.q.128" => "__builtin_ia32_pmovzxbq128_mask",
+    "llvm.x86.avx512.mask.pmovzxb.q.256" => "__builtin_ia32_pmovzxbq256_mask",
+    "llvm.x86.avx512.mask.pmovzxb.q.512" => "__builtin_ia32_pmovzxbq512_mask",
+    "llvm.x86.avx512.mask.pmovzxb.w.128" => "__builtin_ia32_pmovzxbw128_mask",
+    "llvm.x86.avx512.mask.pmovzxb.w.256" => "__builtin_ia32_pmovzxbw256_mask",
+    "llvm.x86.avx512.mask.pmovzxb.w.512" => "__builtin_ia32_pmovzxbw512_mask",
+    "llvm.x86.avx512.mask.pmovzxd.q.128" => "__builtin_ia32_pmovzxdq128_mask",
+    "llvm.x86.avx512.mask.pmovzxd.q.256" => "__builtin_ia32_pmovzxdq256_mask",
+    "llvm.x86.avx512.mask.pmovzxd.q.512" => "__builtin_ia32_pmovzxdq512_mask",
+    "llvm.x86.avx512.mask.pmovzxw.d.128" => "__builtin_ia32_pmovzxwd128_mask",
+    "llvm.x86.avx512.mask.pmovzxw.d.256" => "__builtin_ia32_pmovzxwd256_mask",
+    "llvm.x86.avx512.mask.pmovzxw.d.512" => "__builtin_ia32_pmovzxwd512_mask",
+    "llvm.x86.avx512.mask.pmovzxw.q.128" => "__builtin_ia32_pmovzxwq128_mask",
+    "llvm.x86.avx512.mask.pmovzxw.q.256" => "__builtin_ia32_pmovzxwq256_mask",
+    "llvm.x86.avx512.mask.pmovzxw.q.512" => "__builtin_ia32_pmovzxwq512_mask",
+    "llvm.x86.avx512.mask.pmul.dq.128" => "__builtin_ia32_pmuldq128_mask",
+    "llvm.x86.avx512.mask.pmul.dq.256" => "__builtin_ia32_pmuldq256_mask",
+    "llvm.x86.avx512.mask.pmul.dq.512" => "__builtin_ia32_pmuldq512_mask",
+    "llvm.x86.avx512.mask.pmul.hr.sw.128" => "__builtin_ia32_pmulhrsw128_mask",
+    "llvm.x86.avx512.mask.pmul.hr.sw.256" => "__builtin_ia32_pmulhrsw256_mask",
+    "llvm.x86.avx512.mask.pmul.hr.sw.512" => "__builtin_ia32_pmulhrsw512_mask",
+    "llvm.x86.avx512.mask.pmulh.w.128" => "__builtin_ia32_pmulhw128_mask",
+    "llvm.x86.avx512.mask.pmulh.w.256" => "__builtin_ia32_pmulhw256_mask",
+    "llvm.x86.avx512.mask.pmulh.w.512" => "__builtin_ia32_pmulhw512_mask",
+    "llvm.x86.avx512.mask.pmulhu.w.128" => "__builtin_ia32_pmulhuw128_mask",
+    "llvm.x86.avx512.mask.pmulhu.w.256" => "__builtin_ia32_pmulhuw256_mask",
+    "llvm.x86.avx512.mask.pmulhu.w.512" => "__builtin_ia32_pmulhuw512_mask",
+    "llvm.x86.avx512.mask.pmull.d.128" => "__builtin_ia32_pmulld128_mask",
+    "llvm.x86.avx512.mask.pmull.d.256" => "__builtin_ia32_pmulld256_mask",
+    "llvm.x86.avx512.mask.pmull.d.512" => "__builtin_ia32_pmulld512_mask",
+    "llvm.x86.avx512.mask.pmull.q.128" => "__builtin_ia32_pmullq128_mask",
+    "llvm.x86.avx512.mask.pmull.q.256" => "__builtin_ia32_pmullq256_mask",
+    "llvm.x86.avx512.mask.pmull.q.512" => "__builtin_ia32_pmullq512_mask",
+    "llvm.x86.avx512.mask.pmull.w.128" => "__builtin_ia32_pmullw128_mask",
+    "llvm.x86.avx512.mask.pmull.w.256" => "__builtin_ia32_pmullw256_mask",
+    "llvm.x86.avx512.mask.pmull.w.512" => "__builtin_ia32_pmullw512_mask",
+    "llvm.x86.avx512.mask.pmultishift.qb.128" => "__builtin_ia32_vpmultishiftqb128_mask",
+    "llvm.x86.avx512.mask.pmultishift.qb.256" => "__builtin_ia32_vpmultishiftqb256_mask",
+    "llvm.x86.avx512.mask.pmultishift.qb.512" => "__builtin_ia32_vpmultishiftqb512_mask",
+    "llvm.x86.avx512.mask.pmulu.dq.128" => "__builtin_ia32_pmuludq128_mask",
+    "llvm.x86.avx512.mask.pmulu.dq.256" => "__builtin_ia32_pmuludq256_mask",
+    "llvm.x86.avx512.mask.pmulu.dq.512" => "__builtin_ia32_pmuludq512_mask",
+    "llvm.x86.avx512.mask.prol.d.128" => "__builtin_ia32_prold128_mask",
+    "llvm.x86.avx512.mask.prol.d.256" => "__builtin_ia32_prold256_mask",
+    "llvm.x86.avx512.mask.prol.d.512" => "__builtin_ia32_prold512_mask",
+    "llvm.x86.avx512.mask.prol.q.128" => "__builtin_ia32_prolq128_mask",
+    "llvm.x86.avx512.mask.prol.q.256" => "__builtin_ia32_prolq256_mask",
+    "llvm.x86.avx512.mask.prol.q.512" => "__builtin_ia32_prolq512_mask",
+    "llvm.x86.avx512.mask.prolv.d.128" => "__builtin_ia32_prolvd128_mask",
+    "llvm.x86.avx512.mask.prolv.d.256" => "__builtin_ia32_prolvd256_mask",
+    "llvm.x86.avx512.mask.prolv.d.512" => "__builtin_ia32_prolvd512_mask",
+    "llvm.x86.avx512.mask.prolv.q.128" => "__builtin_ia32_prolvq128_mask",
+    "llvm.x86.avx512.mask.prolv.q.256" => "__builtin_ia32_prolvq256_mask",
+    "llvm.x86.avx512.mask.prolv.q.512" => "__builtin_ia32_prolvq512_mask",
+    "llvm.x86.avx512.mask.pror.d.128" => "__builtin_ia32_prord128_mask",
+    "llvm.x86.avx512.mask.pror.d.256" => "__builtin_ia32_prord256_mask",
+    "llvm.x86.avx512.mask.pror.d.512" => "__builtin_ia32_prord512_mask",
+    "llvm.x86.avx512.mask.pror.q.128" => "__builtin_ia32_prorq128_mask",
+    "llvm.x86.avx512.mask.pror.q.256" => "__builtin_ia32_prorq256_mask",
+    "llvm.x86.avx512.mask.pror.q.512" => "__builtin_ia32_prorq512_mask",
+    "llvm.x86.avx512.mask.prorv.d.128" => "__builtin_ia32_prorvd128_mask",
+    "llvm.x86.avx512.mask.prorv.d.256" => "__builtin_ia32_prorvd256_mask",
+    "llvm.x86.avx512.mask.prorv.d.512" => "__builtin_ia32_prorvd512_mask",
+    "llvm.x86.avx512.mask.prorv.q.128" => "__builtin_ia32_prorvq128_mask",
+    "llvm.x86.avx512.mask.prorv.q.256" => "__builtin_ia32_prorvq256_mask",
+    "llvm.x86.avx512.mask.prorv.q.512" => "__builtin_ia32_prorvq512_mask",
+    "llvm.x86.avx512.mask.pshuf.b.128" => "__builtin_ia32_pshufb128_mask",
+    "llvm.x86.avx512.mask.pshuf.b.256" => "__builtin_ia32_pshufb256_mask",
+    "llvm.x86.avx512.mask.pshuf.b.512" => "__builtin_ia32_pshufb512_mask",
+    "llvm.x86.avx512.mask.psll.d" => "__builtin_ia32_pslld512_mask",
+    "llvm.x86.avx512.mask.psll.d.128" => "__builtin_ia32_pslld128_mask",
+    "llvm.x86.avx512.mask.psll.d.256" => "__builtin_ia32_pslld256_mask",
+    "llvm.x86.avx512.mask.psll.di.128" => "__builtin_ia32_pslldi128_mask",
+    "llvm.x86.avx512.mask.psll.di.256" => "__builtin_ia32_pslldi256_mask",
+    "llvm.x86.avx512.mask.psll.di.512" => "__builtin_ia32_pslldi512_mask",
+    "llvm.x86.avx512.mask.psll.q" => "__builtin_ia32_psllq512_mask",
+    "llvm.x86.avx512.mask.psll.q.128" => "__builtin_ia32_psllq128_mask",
+    "llvm.x86.avx512.mask.psll.q.256" => "__builtin_ia32_psllq256_mask",
+    "llvm.x86.avx512.mask.psll.qi.128" => "__builtin_ia32_psllqi128_mask",
+    "llvm.x86.avx512.mask.psll.qi.256" => "__builtin_ia32_psllqi256_mask",
+    "llvm.x86.avx512.mask.psll.qi.512" => "__builtin_ia32_psllqi512_mask",
+    "llvm.x86.avx512.mask.psll.w.128" => "__builtin_ia32_psllw128_mask",
+    "llvm.x86.avx512.mask.psll.w.256" => "__builtin_ia32_psllw256_mask",
+    "llvm.x86.avx512.mask.psll.w.512" => "__builtin_ia32_psllw512_mask",
+    "llvm.x86.avx512.mask.psll.wi.128" => "__builtin_ia32_psllwi128_mask",
+    "llvm.x86.avx512.mask.psll.wi.256" => "__builtin_ia32_psllwi256_mask",
+    "llvm.x86.avx512.mask.psll.wi.512" => "__builtin_ia32_psllwi512_mask",
+    "llvm.x86.avx512.mask.psllv.d" => "__builtin_ia32_psllv16si_mask",
+    "llvm.x86.avx512.mask.psllv.q" => "__builtin_ia32_psllv8di_mask",
+    "llvm.x86.avx512.mask.psllv16.hi" => "__builtin_ia32_psllv16hi_mask",
+    "llvm.x86.avx512.mask.psllv2.di" => "__builtin_ia32_psllv2di_mask",
+    "llvm.x86.avx512.mask.psllv32hi" => "__builtin_ia32_psllv32hi_mask",
+    "llvm.x86.avx512.mask.psllv4.di" => "__builtin_ia32_psllv4di_mask",
+    "llvm.x86.avx512.mask.psllv4.si" => "__builtin_ia32_psllv4si_mask",
+    "llvm.x86.avx512.mask.psllv8.hi" => "__builtin_ia32_psllv8hi_mask",
+    "llvm.x86.avx512.mask.psllv8.si" => "__builtin_ia32_psllv8si_mask",
+    "llvm.x86.avx512.mask.psra.d" => "__builtin_ia32_psrad512_mask",
+    "llvm.x86.avx512.mask.psra.d.128" => "__builtin_ia32_psrad128_mask",
+    "llvm.x86.avx512.mask.psra.d.256" => "__builtin_ia32_psrad256_mask",
+    "llvm.x86.avx512.mask.psra.di.128" => "__builtin_ia32_psradi128_mask",
+    "llvm.x86.avx512.mask.psra.di.256" => "__builtin_ia32_psradi256_mask",
+    "llvm.x86.avx512.mask.psra.di.512" => "__builtin_ia32_psradi512_mask",
+    "llvm.x86.avx512.mask.psra.q" => "__builtin_ia32_psraq512_mask",
+    "llvm.x86.avx512.mask.psra.q.128" => "__builtin_ia32_psraq128_mask",
+    "llvm.x86.avx512.mask.psra.q.256" => "__builtin_ia32_psraq256_mask",
+    "llvm.x86.avx512.mask.psra.qi.128" => "__builtin_ia32_psraqi128_mask",
+    "llvm.x86.avx512.mask.psra.qi.256" => "__builtin_ia32_psraqi256_mask",
+    "llvm.x86.avx512.mask.psra.qi.512" => "__builtin_ia32_psraqi512_mask",
+    "llvm.x86.avx512.mask.psra.w.128" => "__builtin_ia32_psraw128_mask",
+    "llvm.x86.avx512.mask.psra.w.256" => "__builtin_ia32_psraw256_mask",
+    "llvm.x86.avx512.mask.psra.w.512" => "__builtin_ia32_psraw512_mask",
+    "llvm.x86.avx512.mask.psra.wi.128" => "__builtin_ia32_psrawi128_mask",
+    "llvm.x86.avx512.mask.psra.wi.256" => "__builtin_ia32_psrawi256_mask",
+    "llvm.x86.avx512.mask.psra.wi.512" => "__builtin_ia32_psrawi512_mask",
+    "llvm.x86.avx512.mask.psrav.d" => "__builtin_ia32_psrav16si_mask",
+    "llvm.x86.avx512.mask.psrav.q" => "__builtin_ia32_psrav8di_mask",
+    "llvm.x86.avx512.mask.psrav.q.128" => "__builtin_ia32_psravq128_mask",
+    "llvm.x86.avx512.mask.psrav.q.256" => "__builtin_ia32_psravq256_mask",
+    "llvm.x86.avx512.mask.psrav16.hi" => "__builtin_ia32_psrav16hi_mask",
+    "llvm.x86.avx512.mask.psrav32.hi" => "__builtin_ia32_psrav32hi_mask",
+    "llvm.x86.avx512.mask.psrav4.si" => "__builtin_ia32_psrav4si_mask",
+    "llvm.x86.avx512.mask.psrav8.hi" => "__builtin_ia32_psrav8hi_mask",
+    "llvm.x86.avx512.mask.psrav8.si" => "__builtin_ia32_psrav8si_mask",
+    "llvm.x86.avx512.mask.psrl.d" => "__builtin_ia32_psrld512_mask",
+    "llvm.x86.avx512.mask.psrl.d.128" => "__builtin_ia32_psrld128_mask",
+    "llvm.x86.avx512.mask.psrl.d.256" => "__builtin_ia32_psrld256_mask",
+    "llvm.x86.avx512.mask.psrl.di.128" => "__builtin_ia32_psrldi128_mask",
+    "llvm.x86.avx512.mask.psrl.di.256" => "__builtin_ia32_psrldi256_mask",
+    "llvm.x86.avx512.mask.psrl.di.512" => "__builtin_ia32_psrldi512_mask",
+    "llvm.x86.avx512.mask.psrl.q" => "__builtin_ia32_psrlq512_mask",
+    "llvm.x86.avx512.mask.psrl.q.128" => "__builtin_ia32_psrlq128_mask",
+    "llvm.x86.avx512.mask.psrl.q.256" => "__builtin_ia32_psrlq256_mask",
+    "llvm.x86.avx512.mask.psrl.qi.128" => "__builtin_ia32_psrlqi128_mask",
+    "llvm.x86.avx512.mask.psrl.qi.256" => "__builtin_ia32_psrlqi256_mask",
+    "llvm.x86.avx512.mask.psrl.qi.512" => "__builtin_ia32_psrlqi512_mask",
+    "llvm.x86.avx512.mask.psrl.w.128" => "__builtin_ia32_psrlw128_mask",
+    "llvm.x86.avx512.mask.psrl.w.256" => "__builtin_ia32_psrlw256_mask",
+    "llvm.x86.avx512.mask.psrl.w.512" => "__builtin_ia32_psrlw512_mask",
+    "llvm.x86.avx512.mask.psrl.wi.128" => "__builtin_ia32_psrlwi128_mask",
+    "llvm.x86.avx512.mask.psrl.wi.256" => "__builtin_ia32_psrlwi256_mask",
+    "llvm.x86.avx512.mask.psrl.wi.512" => "__builtin_ia32_psrlwi512_mask",
+    "llvm.x86.avx512.mask.psrlv.d" => "__builtin_ia32_psrlv16si_mask",
+    "llvm.x86.avx512.mask.psrlv.q" => "__builtin_ia32_psrlv8di_mask",
+    "llvm.x86.avx512.mask.psrlv16.hi" => "__builtin_ia32_psrlv16hi_mask",
+    "llvm.x86.avx512.mask.psrlv2.di" => "__builtin_ia32_psrlv2di_mask",
+    "llvm.x86.avx512.mask.psrlv32hi" => "__builtin_ia32_psrlv32hi_mask",
+    "llvm.x86.avx512.mask.psrlv4.di" => "__builtin_ia32_psrlv4di_mask",
+    "llvm.x86.avx512.mask.psrlv4.si" => "__builtin_ia32_psrlv4si_mask",
+    "llvm.x86.avx512.mask.psrlv8.hi" => "__builtin_ia32_psrlv8hi_mask",
+    "llvm.x86.avx512.mask.psrlv8.si" => "__builtin_ia32_psrlv8si_mask",
+    "llvm.x86.avx512.mask.psub.b.128" => "__builtin_ia32_psubb128_mask",
+    "llvm.x86.avx512.mask.psub.b.256" => "__builtin_ia32_psubb256_mask",
+    "llvm.x86.avx512.mask.psub.b.512" => "__builtin_ia32_psubb512_mask",
+    "llvm.x86.avx512.mask.psub.d.128" => "__builtin_ia32_psubd128_mask",
+    "llvm.x86.avx512.mask.psub.d.256" => "__builtin_ia32_psubd256_mask",
+    "llvm.x86.avx512.mask.psub.d.512" => "__builtin_ia32_psubd512_mask",
+    "llvm.x86.avx512.mask.psub.q.128" => "__builtin_ia32_psubq128_mask",
+    "llvm.x86.avx512.mask.psub.q.256" => "__builtin_ia32_psubq256_mask",
+    "llvm.x86.avx512.mask.psub.q.512" => "__builtin_ia32_psubq512_mask",
+    "llvm.x86.avx512.mask.psub.w.128" => "__builtin_ia32_psubw128_mask",
+    "llvm.x86.avx512.mask.psub.w.256" => "__builtin_ia32_psubw256_mask",
+    "llvm.x86.avx512.mask.psub.w.512" => "__builtin_ia32_psubw512_mask",
+    "llvm.x86.avx512.mask.psubs.b.128" => "__builtin_ia32_psubsb128_mask",
+    "llvm.x86.avx512.mask.psubs.b.256" => "__builtin_ia32_psubsb256_mask",
+    "llvm.x86.avx512.mask.psubs.b.512" => "__builtin_ia32_psubsb512_mask",
+    "llvm.x86.avx512.mask.psubs.w.128" => "__builtin_ia32_psubsw128_mask",
+    "llvm.x86.avx512.mask.psubs.w.256" => "__builtin_ia32_psubsw256_mask",
+    "llvm.x86.avx512.mask.psubs.w.512" => "__builtin_ia32_psubsw512_mask",
+    "llvm.x86.avx512.mask.psubus.b.128" => "__builtin_ia32_psubusb128_mask",
+    "llvm.x86.avx512.mask.psubus.b.256" => "__builtin_ia32_psubusb256_mask",
+    "llvm.x86.avx512.mask.psubus.b.512" => "__builtin_ia32_psubusb512_mask",
+    "llvm.x86.avx512.mask.psubus.w.128" => "__builtin_ia32_psubusw128_mask",
+    "llvm.x86.avx512.mask.psubus.w.256" => "__builtin_ia32_psubusw256_mask",
+    "llvm.x86.avx512.mask.psubus.w.512" => "__builtin_ia32_psubusw512_mask",
+    "llvm.x86.avx512.mask.pternlog.d.128" => "__builtin_ia32_pternlogd128_mask",
+    "llvm.x86.avx512.mask.pternlog.d.256" => "__builtin_ia32_pternlogd256_mask",
+    "llvm.x86.avx512.mask.pternlog.d.512" => "__builtin_ia32_pternlogd512_mask",
+    "llvm.x86.avx512.mask.pternlog.q.128" => "__builtin_ia32_pternlogq128_mask",
+    "llvm.x86.avx512.mask.pternlog.q.256" => "__builtin_ia32_pternlogq256_mask",
+    "llvm.x86.avx512.mask.pternlog.q.512" => "__builtin_ia32_pternlogq512_mask",
+    "llvm.x86.avx512.mask.ptestm.d.512" => "__builtin_ia32_ptestmd512",
+    "llvm.x86.avx512.mask.ptestm.q.512" => "__builtin_ia32_ptestmq512",
+    "llvm.x86.avx512.mask.range.pd.128" => "__builtin_ia32_rangepd128_mask",
+    "llvm.x86.avx512.mask.range.pd.256" => "__builtin_ia32_rangepd256_mask",
+    "llvm.x86.avx512.mask.range.pd.512" => "__builtin_ia32_rangepd512_mask",
+    "llvm.x86.avx512.mask.range.ps.128" => "__builtin_ia32_rangeps128_mask",
+    "llvm.x86.avx512.mask.range.ps.256" => "__builtin_ia32_rangeps256_mask",
+    "llvm.x86.avx512.mask.range.ps.512" => "__builtin_ia32_rangeps512_mask",
+    "llvm.x86.avx512.mask.range.sd" => "__builtin_ia32_rangesd128_round_mask",
+    "llvm.x86.avx512.mask.range.ss" => "__builtin_ia32_rangess128_round_mask",
+    "llvm.x86.avx512.mask.reduce.pd.128" => "__builtin_ia32_reducepd128_mask",
+    "llvm.x86.avx512.mask.reduce.pd.256" => "__builtin_ia32_reducepd256_mask",
+    "llvm.x86.avx512.mask.reduce.pd.512" => "__builtin_ia32_reducepd512_mask",
+    "llvm.x86.avx512.mask.reduce.ps.128" => "__builtin_ia32_reduceps128_mask",
+    "llvm.x86.avx512.mask.reduce.ps.256" => "__builtin_ia32_reduceps256_mask",
+    "llvm.x86.avx512.mask.reduce.ps.512" => "__builtin_ia32_reduceps512_mask",
+    "llvm.x86.avx512.mask.reduce.sd" => "__builtin_ia32_reducesd_mask",
+    "llvm.x86.avx512.mask.reduce.ss" => "__builtin_ia32_reducess_mask",
+    "llvm.x86.avx512.mask.rndscale.pd.128" => "__builtin_ia32_rndscalepd_128_mask",
+    "llvm.x86.avx512.mask.rndscale.pd.256" => "__builtin_ia32_rndscalepd_256_mask",
+    "llvm.x86.avx512.mask.rndscale.pd.512" => "__builtin_ia32_rndscalepd_mask",
+    "llvm.x86.avx512.mask.rndscale.ps.128" => "__builtin_ia32_rndscaleps_128_mask",
+    "llvm.x86.avx512.mask.rndscale.ps.256" => "__builtin_ia32_rndscaleps_256_mask",
+    "llvm.x86.avx512.mask.rndscale.ps.512" => "__builtin_ia32_rndscaleps_mask",
+    "llvm.x86.avx512.mask.rndscale.sd" => "__builtin_ia32_rndscalesd_round_mask",
+    "llvm.x86.avx512.mask.rndscale.ss" => "__builtin_ia32_rndscaless_round_mask",
+    "llvm.x86.avx512.mask.scalef.pd.128" => "__builtin_ia32_scalefpd128_mask",
+    "llvm.x86.avx512.mask.scalef.pd.256" => "__builtin_ia32_scalefpd256_mask",
+    "llvm.x86.avx512.mask.scalef.pd.512" => "__builtin_ia32_scalefpd512_mask",
+    "llvm.x86.avx512.mask.scalef.ps.128" => "__builtin_ia32_scalefps128_mask",
+    "llvm.x86.avx512.mask.scalef.ps.256" => "__builtin_ia32_scalefps256_mask",
+    "llvm.x86.avx512.mask.scalef.ps.512" => "__builtin_ia32_scalefps512_mask",
+    "llvm.x86.avx512.mask.scalef.sd" => "__builtin_ia32_scalefsd_round_mask",
+    "llvm.x86.avx512.mask.scalef.ss" => "__builtin_ia32_scalefss_round_mask",
+    "llvm.x86.avx512.mask.shuf.f32x4" => "__builtin_ia32_shuf_f32x4_mask",
+    "llvm.x86.avx512.mask.shuf.f32x4.256" => "__builtin_ia32_shuf_f32x4_256_mask",
+    "llvm.x86.avx512.mask.shuf.f64x2" => "__builtin_ia32_shuf_f64x2_mask",
+    "llvm.x86.avx512.mask.shuf.f64x2.256" => "__builtin_ia32_shuf_f64x2_256_mask",
+    "llvm.x86.avx512.mask.shuf.i32x4" => "__builtin_ia32_shuf_i32x4_mask",
+    "llvm.x86.avx512.mask.shuf.i32x4.256" => "__builtin_ia32_shuf_i32x4_256_mask",
+    "llvm.x86.avx512.mask.shuf.i64x2" => "__builtin_ia32_shuf_i64x2_mask",
+    "llvm.x86.avx512.mask.shuf.i64x2.256" => "__builtin_ia32_shuf_i64x2_256_mask",
+    "llvm.x86.avx512.mask.shuf.pd.128" => "__builtin_ia32_shufpd128_mask",
+    "llvm.x86.avx512.mask.shuf.pd.256" => "__builtin_ia32_shufpd256_mask",
+    "llvm.x86.avx512.mask.shuf.pd.512" => "__builtin_ia32_shufpd512_mask",
+    "llvm.x86.avx512.mask.shuf.ps.128" => "__builtin_ia32_shufps128_mask",
+    "llvm.x86.avx512.mask.shuf.ps.256" => "__builtin_ia32_shufps256_mask",
+    "llvm.x86.avx512.mask.shuf.ps.512" => "__builtin_ia32_shufps512_mask",
+    "llvm.x86.avx512.mask.sqrt.pd.128" => "__builtin_ia32_sqrtpd128_mask",
+    "llvm.x86.avx512.mask.sqrt.pd.256" => "__builtin_ia32_sqrtpd256_mask",
+    "llvm.x86.avx512.mask.sqrt.pd.512" => "__builtin_ia32_sqrtpd512_mask",
+    "llvm.x86.avx512.mask.sqrt.ps.128" => "__builtin_ia32_sqrtps128_mask",
+    "llvm.x86.avx512.mask.sqrt.ps.256" => "__builtin_ia32_sqrtps256_mask",
+    "llvm.x86.avx512.mask.sqrt.ps.512" => "__builtin_ia32_sqrtps512_mask",
+    "llvm.x86.avx512.mask.sqrt.sd" => "__builtin_ia32_sqrtsd_round_mask",
+    "llvm.x86.avx512.mask.sqrt.ss" => "__builtin_ia32_sqrtss_round_mask",
+    "llvm.x86.avx512.mask.store.ss" => "__builtin_ia32_storess_mask",
+    "llvm.x86.avx512.mask.storeu.d.512" => "__builtin_ia32_storedqusi512_mask",
+    "llvm.x86.avx512.mask.storeu.pd.512" => "__builtin_ia32_storeupd512_mask",
+    "llvm.x86.avx512.mask.storeu.ps.512" => "__builtin_ia32_storeups512_mask",
+    "llvm.x86.avx512.mask.storeu.q.512" => "__builtin_ia32_storedqudi512_mask",
+    "llvm.x86.avx512.mask.sub.pd.128" => "__builtin_ia32_subpd128_mask",
+    "llvm.x86.avx512.mask.sub.pd.256" => "__builtin_ia32_subpd256_mask",
+    "llvm.x86.avx512.mask.sub.pd.512" => "__builtin_ia32_subpd512_mask",
+    "llvm.x86.avx512.mask.sub.ps.128" => "__builtin_ia32_subps128_mask",
+    "llvm.x86.avx512.mask.sub.ps.256" => "__builtin_ia32_subps256_mask",
+    "llvm.x86.avx512.mask.sub.ps.512" => "__builtin_ia32_subps512_mask",
+    "llvm.x86.avx512.mask.sub.sd.round" => "__builtin_ia32_subsd_round_mask",
+    "llvm.x86.avx512.mask.sub.ss.round" => "__builtin_ia32_subss_round_mask",
+    "llvm.x86.avx512.mask.valign.d.128" => "__builtin_ia32_alignd128_mask",
+    "llvm.x86.avx512.mask.valign.d.256" => "__builtin_ia32_alignd256_mask",
+    "llvm.x86.avx512.mask.valign.d.512" => "__builtin_ia32_alignd512_mask",
+    "llvm.x86.avx512.mask.valign.q.128" => "__builtin_ia32_alignq128_mask",
+    "llvm.x86.avx512.mask.valign.q.256" => "__builtin_ia32_alignq256_mask",
+    "llvm.x86.avx512.mask.valign.q.512" => "__builtin_ia32_alignq512_mask",
+    "llvm.x86.avx512.mask.vcvtph2ps.128" => "__builtin_ia32_vcvtph2ps_mask",
+    "llvm.x86.avx512.mask.vcvtph2ps.256" => "__builtin_ia32_vcvtph2ps256_mask",
+    "llvm.x86.avx512.mask.vcvtph2ps.512" => "__builtin_ia32_vcvtph2ps512_mask",
+    "llvm.x86.avx512.mask.vcvtps2ph.128" => "__builtin_ia32_vcvtps2ph_mask",
+    "llvm.x86.avx512.mask.vcvtps2ph.256" => "__builtin_ia32_vcvtps2ph256_mask",
+    "llvm.x86.avx512.mask.vcvtps2ph.512" => "__builtin_ia32_vcvtps2ph512_mask",
+    "llvm.x86.avx512.mask.vextractf32x4.256" => "__builtin_ia32_extractf32x4_256_mask",
+    "llvm.x86.avx512.mask.vextractf32x4.512" => "__builtin_ia32_extractf32x4_mask",
+    "llvm.x86.avx512.mask.vextractf32x8.512" => "__builtin_ia32_extractf32x8_mask",
+    "llvm.x86.avx512.mask.vextractf64x2.256" => "__builtin_ia32_extractf64x2_256_mask",
+    "llvm.x86.avx512.mask.vextractf64x2.512" => "__builtin_ia32_extractf64x2_512_mask",
+    "llvm.x86.avx512.mask.vextractf64x4.512" => "__builtin_ia32_extractf64x4_mask",
+    "llvm.x86.avx512.mask.vextracti32x4.256" => "__builtin_ia32_extracti32x4_256_mask",
+    "llvm.x86.avx512.mask.vextracti32x4.512" => "__builtin_ia32_extracti32x4_mask",
+    "llvm.x86.avx512.mask.vextracti32x8.512" => "__builtin_ia32_extracti32x8_mask",
+    "llvm.x86.avx512.mask.vextracti64x2.256" => "__builtin_ia32_extracti64x2_256_mask",
+    "llvm.x86.avx512.mask.vextracti64x2.512" => "__builtin_ia32_extracti64x2_512_mask",
+    "llvm.x86.avx512.mask.vextracti64x4.512" => "__builtin_ia32_extracti64x4_mask",
+    "llvm.x86.avx512.mask.vfmadd.pd.128" => "__builtin_ia32_vfmaddpd128_mask",
+    "llvm.x86.avx512.mask.vfmadd.pd.256" => "__builtin_ia32_vfmaddpd256_mask",
+    "llvm.x86.avx512.mask.vfmadd.pd.512" => "__builtin_ia32_vfmaddpd512_mask",
+    "llvm.x86.avx512.mask.vfmadd.ps.128" => "__builtin_ia32_vfmaddps128_mask",
+    "llvm.x86.avx512.mask.vfmadd.ps.256" => "__builtin_ia32_vfmaddps256_mask",
+    "llvm.x86.avx512.mask.vfmadd.ps.512" => "__builtin_ia32_vfmaddps512_mask",
+    "llvm.x86.avx512.mask.vfmadd.sd" => "__builtin_ia32_vfmaddsd3_mask",
+    "llvm.x86.avx512.mask.vfmadd.ss" => "__builtin_ia32_vfmaddss3_mask",
+    "llvm.x86.avx512.mask.vfmaddsub.pd.128" => "__builtin_ia32_vfmaddsubpd128_mask",
+    "llvm.x86.avx512.mask.vfmaddsub.pd.256" => "__builtin_ia32_vfmaddsubpd256_mask",
+    "llvm.x86.avx512.mask.vfmaddsub.pd.512" => "__builtin_ia32_vfmaddsubpd512_mask",
+    "llvm.x86.avx512.mask.vfmaddsub.ps.128" => "__builtin_ia32_vfmaddsubps128_mask",
+    "llvm.x86.avx512.mask.vfmaddsub.ps.256" => "__builtin_ia32_vfmaddsubps256_mask",
+    "llvm.x86.avx512.mask.vfmaddsub.ps.512" => "__builtin_ia32_vfmaddsubps512_mask",
+    "llvm.x86.avx512.mask.vfnmadd.pd.128" => "__builtin_ia32_vfnmaddpd128_mask",
+    "llvm.x86.avx512.mask.vfnmadd.pd.256" => "__builtin_ia32_vfnmaddpd256_mask",
+    "llvm.x86.avx512.mask.vfnmadd.pd.512" => "__builtin_ia32_vfnmaddpd512_mask",
+    "llvm.x86.avx512.mask.vfnmadd.ps.128" => "__builtin_ia32_vfnmaddps128_mask",
+    "llvm.x86.avx512.mask.vfnmadd.ps.256" => "__builtin_ia32_vfnmaddps256_mask",
+    "llvm.x86.avx512.mask.vfnmadd.ps.512" => "__builtin_ia32_vfnmaddps512_mask",
+    "llvm.x86.avx512.mask.vfnmsub.pd.128" => "__builtin_ia32_vfnmsubpd128_mask",
+    "llvm.x86.avx512.mask.vfnmsub.pd.256" => "__builtin_ia32_vfnmsubpd256_mask",
+    "llvm.x86.avx512.mask.vfnmsub.pd.512" => "__builtin_ia32_vfnmsubpd512_mask",
+    "llvm.x86.avx512.mask.vfnmsub.ps.128" => "__builtin_ia32_vfnmsubps128_mask",
+    "llvm.x86.avx512.mask.vfnmsub.ps.256" => "__builtin_ia32_vfnmsubps256_mask",
+    "llvm.x86.avx512.mask.vfnmsub.ps.512" => "__builtin_ia32_vfnmsubps512_mask",
+    "llvm.x86.avx512.mask.vpermi2var.d.128" => "__builtin_ia32_vpermi2vard128_mask",
+    "llvm.x86.avx512.mask.vpermi2var.d.256" => "__builtin_ia32_vpermi2vard256_mask",
+    "llvm.x86.avx512.mask.vpermi2var.d.512" => "__builtin_ia32_vpermi2vard512_mask",
+    "llvm.x86.avx512.mask.vpermi2var.hi.128" => "__builtin_ia32_vpermi2varhi128_mask",
+    "llvm.x86.avx512.mask.vpermi2var.hi.256" => "__builtin_ia32_vpermi2varhi256_mask",
+    "llvm.x86.avx512.mask.vpermi2var.hi.512" => "__builtin_ia32_vpermi2varhi512_mask",
+    "llvm.x86.avx512.mask.vpermi2var.pd.128" => "__builtin_ia32_vpermi2varpd128_mask",
+    "llvm.x86.avx512.mask.vpermi2var.pd.256" => "__builtin_ia32_vpermi2varpd256_mask",
+    "llvm.x86.avx512.mask.vpermi2var.pd.512" => "__builtin_ia32_vpermi2varpd512_mask",
+    "llvm.x86.avx512.mask.vpermi2var.ps.128" => "__builtin_ia32_vpermi2varps128_mask",
+    "llvm.x86.avx512.mask.vpermi2var.ps.256" => "__builtin_ia32_vpermi2varps256_mask",
+    "llvm.x86.avx512.mask.vpermi2var.ps.512" => "__builtin_ia32_vpermi2varps512_mask",
+    "llvm.x86.avx512.mask.vpermi2var.q.128" => "__builtin_ia32_vpermi2varq128_mask",
+    "llvm.x86.avx512.mask.vpermi2var.q.256" => "__builtin_ia32_vpermi2varq256_mask",
+    "llvm.x86.avx512.mask.vpermi2var.q.512" => "__builtin_ia32_vpermi2varq512_mask",
+    "llvm.x86.avx512.mask.vpermi2var.qi.128" => "__builtin_ia32_vpermi2varqi128_mask",
+    "llvm.x86.avx512.mask.vpermi2var.qi.256" => "__builtin_ia32_vpermi2varqi256_mask",
+    "llvm.x86.avx512.mask.vpermi2var.qi.512" => "__builtin_ia32_vpermi2varqi512_mask",
+    "llvm.x86.avx512.mask.vpermilvar.pd.128" => "__builtin_ia32_vpermilvarpd_mask",
+    "llvm.x86.avx512.mask.vpermilvar.pd.256" => "__builtin_ia32_vpermilvarpd256_mask",
+    "llvm.x86.avx512.mask.vpermilvar.pd.512" => "__builtin_ia32_vpermilvarpd512_mask",
+    "llvm.x86.avx512.mask.vpermilvar.ps.128" => "__builtin_ia32_vpermilvarps_mask",
+    "llvm.x86.avx512.mask.vpermilvar.ps.256" => "__builtin_ia32_vpermilvarps256_mask",
+    "llvm.x86.avx512.mask.vpermilvar.ps.512" => "__builtin_ia32_vpermilvarps512_mask",
+    "llvm.x86.avx512.mask.vpermt.d.512" => "__builtin_ia32_vpermt2vard512_mask",
+    "llvm.x86.avx512.mask.vpermt.pd.512" => "__builtin_ia32_vpermt2varpd512_mask",
+    "llvm.x86.avx512.mask.vpermt.ps.512" => "__builtin_ia32_vpermt2varps512_mask",
+    "llvm.x86.avx512.mask.vpermt.q.512" => "__builtin_ia32_vpermt2varq512_mask",
+    "llvm.x86.avx512.mask.vpermt2var.d.128" => "__builtin_ia32_vpermt2vard128_mask",
+    "llvm.x86.avx512.mask.vpermt2var.d.256" => "__builtin_ia32_vpermt2vard256_mask",
+    "llvm.x86.avx512.mask.vpermt2var.d.512" => "__builtin_ia32_vpermt2vard512_mask",
+    "llvm.x86.avx512.mask.vpermt2var.hi.128" => "__builtin_ia32_vpermt2varhi128_mask",
+    "llvm.x86.avx512.mask.vpermt2var.hi.256" => "__builtin_ia32_vpermt2varhi256_mask",
+    "llvm.x86.avx512.mask.vpermt2var.hi.512" => "__builtin_ia32_vpermt2varhi512_mask",
+    "llvm.x86.avx512.mask.vpermt2var.pd.128" => "__builtin_ia32_vpermt2varpd128_mask",
+    "llvm.x86.avx512.mask.vpermt2var.pd.256" => "__builtin_ia32_vpermt2varpd256_mask",
+    "llvm.x86.avx512.mask.vpermt2var.pd.512" => "__builtin_ia32_vpermt2varpd512_mask",
+    "llvm.x86.avx512.mask.vpermt2var.ps.128" => "__builtin_ia32_vpermt2varps128_mask",
+    "llvm.x86.avx512.mask.vpermt2var.ps.256" => "__builtin_ia32_vpermt2varps256_mask",
+    "llvm.x86.avx512.mask.vpermt2var.ps.512" => "__builtin_ia32_vpermt2varps512_mask",
+    "llvm.x86.avx512.mask.vpermt2var.q.128" => "__builtin_ia32_vpermt2varq128_mask",
+    "llvm.x86.avx512.mask.vpermt2var.q.256" => "__builtin_ia32_vpermt2varq256_mask",
+    "llvm.x86.avx512.mask.vpermt2var.q.512" => "__builtin_ia32_vpermt2varq512_mask",
+    "llvm.x86.avx512.mask.vpermt2var.qi.128" => "__builtin_ia32_vpermt2varqi128_mask",
+    "llvm.x86.avx512.mask.vpermt2var.qi.256" => "__builtin_ia32_vpermt2varqi256_mask",
+    "llvm.x86.avx512.mask.vpermt2var.qi.512" => "__builtin_ia32_vpermt2varqi512_mask",
+    "llvm.x86.avx512.mask.vpmadd52h.uq.128" => "__builtin_ia32_vpmadd52huq128_mask",
+    "llvm.x86.avx512.mask.vpmadd52h.uq.256" => "__builtin_ia32_vpmadd52huq256_mask",
+    "llvm.x86.avx512.mask.vpmadd52h.uq.512" => "__builtin_ia32_vpmadd52huq512_mask",
+    "llvm.x86.avx512.mask.vpmadd52l.uq.128" => "__builtin_ia32_vpmadd52luq128_mask",
+    "llvm.x86.avx512.mask.vpmadd52l.uq.256" => "__builtin_ia32_vpmadd52luq256_mask",
+    "llvm.x86.avx512.mask.vpmadd52l.uq.512" => "__builtin_ia32_vpmadd52luq512_mask",
+    "llvm.x86.avx512.mask.xor.pd.128" => "__builtin_ia32_xorpd128_mask",
+    "llvm.x86.avx512.mask.xor.pd.256" => "__builtin_ia32_xorpd256_mask",
+    "llvm.x86.avx512.mask.xor.pd.512" => "__builtin_ia32_xorpd512_mask",
+    "llvm.x86.avx512.mask.xor.ps.128" => "__builtin_ia32_xorps128_mask",
+    "llvm.x86.avx512.mask.xor.ps.256" => "__builtin_ia32_xorps256_mask",
+    "llvm.x86.avx512.mask.xor.ps.512" => "__builtin_ia32_xorps512_mask",
+    "llvm.x86.avx512.mask3.vfmadd.pd.128" => "__builtin_ia32_vfmaddpd128_mask3",
+    "llvm.x86.avx512.mask3.vfmadd.pd.256" => "__builtin_ia32_vfmaddpd256_mask3",
+    "llvm.x86.avx512.mask3.vfmadd.pd.512" => "__builtin_ia32_vfmaddpd512_mask3",
+    "llvm.x86.avx512.mask3.vfmadd.ps.128" => "__builtin_ia32_vfmaddps128_mask3",
+    "llvm.x86.avx512.mask3.vfmadd.ps.256" => "__builtin_ia32_vfmaddps256_mask3",
+    "llvm.x86.avx512.mask3.vfmadd.ps.512" => "__builtin_ia32_vfmaddps512_mask3",
+    "llvm.x86.avx512.mask3.vfmadd.sd" => "__builtin_ia32_vfmaddsd3_mask3",
+    "llvm.x86.avx512.mask3.vfmadd.ss" => "__builtin_ia32_vfmaddss3_mask3",
+    "llvm.x86.avx512.mask3.vfmaddsub.pd.128" => "__builtin_ia32_vfmaddsubpd128_mask3",
+    "llvm.x86.avx512.mask3.vfmaddsub.pd.256" => "__builtin_ia32_vfmaddsubpd256_mask3",
+    "llvm.x86.avx512.mask3.vfmaddsub.pd.512" => "__builtin_ia32_vfmaddsubpd512_mask3",
+    "llvm.x86.avx512.mask3.vfmaddsub.ps.128" => "__builtin_ia32_vfmaddsubps128_mask3",
+    "llvm.x86.avx512.mask3.vfmaddsub.ps.256" => "__builtin_ia32_vfmaddsubps256_mask3",
+    "llvm.x86.avx512.mask3.vfmaddsub.ps.512" => "__builtin_ia32_vfmaddsubps512_mask3",
+    "llvm.x86.avx512.mask3.vfmsub.pd.128" => "__builtin_ia32_vfmsubpd128_mask3",
+    "llvm.x86.avx512.mask3.vfmsub.pd.256" => "__builtin_ia32_vfmsubpd256_mask3",
+    "llvm.x86.avx512.mask3.vfmsub.pd.512" => "__builtin_ia32_vfmsubpd512_mask3",
+    "llvm.x86.avx512.mask3.vfmsub.ps.128" => "__builtin_ia32_vfmsubps128_mask3",
+    "llvm.x86.avx512.mask3.vfmsub.ps.256" => "__builtin_ia32_vfmsubps256_mask3",
+    "llvm.x86.avx512.mask3.vfmsub.ps.512" => "__builtin_ia32_vfmsubps512_mask3",
+    "llvm.x86.avx512.mask3.vfmsubadd.pd.128" => "__builtin_ia32_vfmsubaddpd128_mask3",
+    "llvm.x86.avx512.mask3.vfmsubadd.pd.256" => "__builtin_ia32_vfmsubaddpd256_mask3",
+    "llvm.x86.avx512.mask3.vfmsubadd.pd.512" => "__builtin_ia32_vfmsubaddpd512_mask3",
+    "llvm.x86.avx512.mask3.vfmsubadd.ps.128" => "__builtin_ia32_vfmsubaddps128_mask3",
+    "llvm.x86.avx512.mask3.vfmsubadd.ps.256" => "__builtin_ia32_vfmsubaddps256_mask3",
+    "llvm.x86.avx512.mask3.vfmsubadd.ps.512" => "__builtin_ia32_vfmsubaddps512_mask3",
+    "llvm.x86.avx512.mask3.vfnmsub.pd.128" => "__builtin_ia32_vfnmsubpd128_mask3",
+    "llvm.x86.avx512.mask3.vfnmsub.pd.256" => "__builtin_ia32_vfnmsubpd256_mask3",
+    "llvm.x86.avx512.mask3.vfnmsub.pd.512" => "__builtin_ia32_vfnmsubpd512_mask3",
+    "llvm.x86.avx512.mask3.vfnmsub.ps.128" => "__builtin_ia32_vfnmsubps128_mask3",
+    "llvm.x86.avx512.mask3.vfnmsub.ps.256" => "__builtin_ia32_vfnmsubps256_mask3",
+    "llvm.x86.avx512.mask3.vfnmsub.ps.512" => "__builtin_ia32_vfnmsubps512_mask3",
+    "llvm.x86.avx512.maskz.fixupimm.pd.128" => "__builtin_ia32_fixupimmpd128_maskz",
+    "llvm.x86.avx512.maskz.fixupimm.pd.256" => "__builtin_ia32_fixupimmpd256_maskz",
+    "llvm.x86.avx512.maskz.fixupimm.pd.512" => "__builtin_ia32_fixupimmpd512_maskz",
+    "llvm.x86.avx512.maskz.fixupimm.ps.128" => "__builtin_ia32_fixupimmps128_maskz",
+    "llvm.x86.avx512.maskz.fixupimm.ps.256" => "__builtin_ia32_fixupimmps256_maskz",
+    "llvm.x86.avx512.maskz.fixupimm.ps.512" => "__builtin_ia32_fixupimmps512_maskz",
+    "llvm.x86.avx512.maskz.fixupimm.sd" => "__builtin_ia32_fixupimmsd_maskz",
+    "llvm.x86.avx512.maskz.fixupimm.ss" => "__builtin_ia32_fixupimmss_maskz",
+    "llvm.x86.avx512.maskz.pternlog.d.128" => "__builtin_ia32_pternlogd128_maskz",
+    "llvm.x86.avx512.maskz.pternlog.d.256" => "__builtin_ia32_pternlogd256_maskz",
+    "llvm.x86.avx512.maskz.pternlog.d.512" => "__builtin_ia32_pternlogd512_maskz",
+    "llvm.x86.avx512.maskz.pternlog.q.128" => "__builtin_ia32_pternlogq128_maskz",
+    "llvm.x86.avx512.maskz.pternlog.q.256" => "__builtin_ia32_pternlogq256_maskz",
+    "llvm.x86.avx512.maskz.pternlog.q.512" => "__builtin_ia32_pternlogq512_maskz",
+    "llvm.x86.avx512.maskz.vfmadd.pd.128" => "__builtin_ia32_vfmaddpd128_maskz",
+    "llvm.x86.avx512.maskz.vfmadd.pd.256" => "__builtin_ia32_vfmaddpd256_maskz",
+    "llvm.x86.avx512.maskz.vfmadd.pd.512" => "__builtin_ia32_vfmaddpd512_maskz",
+    "llvm.x86.avx512.maskz.vfmadd.ps.128" => "__builtin_ia32_vfmaddps128_maskz",
+    "llvm.x86.avx512.maskz.vfmadd.ps.256" => "__builtin_ia32_vfmaddps256_maskz",
+    "llvm.x86.avx512.maskz.vfmadd.ps.512" => "__builtin_ia32_vfmaddps512_maskz",
+    "llvm.x86.avx512.maskz.vfmadd.sd" => "__builtin_ia32_vfmaddsd3_maskz",
+    "llvm.x86.avx512.maskz.vfmadd.ss" => "__builtin_ia32_vfmaddss3_maskz",
+    "llvm.x86.avx512.maskz.vfmaddsub.pd.128" => "__builtin_ia32_vfmaddsubpd128_maskz",
+    "llvm.x86.avx512.maskz.vfmaddsub.pd.256" => "__builtin_ia32_vfmaddsubpd256_maskz",
+    "llvm.x86.avx512.maskz.vfmaddsub.pd.512" => "__builtin_ia32_vfmaddsubpd512_maskz",
+    "llvm.x86.avx512.maskz.vfmaddsub.ps.128" => "__builtin_ia32_vfmaddsubps128_maskz",
+    "llvm.x86.avx512.maskz.vfmaddsub.ps.256" => "__builtin_ia32_vfmaddsubps256_maskz",
+    "llvm.x86.avx512.maskz.vfmaddsub.ps.512" => "__builtin_ia32_vfmaddsubps512_maskz",
+    "llvm.x86.avx512.maskz.vpermt2var.d.128" => "__builtin_ia32_vpermt2vard128_maskz",
+    "llvm.x86.avx512.maskz.vpermt2var.d.256" => "__builtin_ia32_vpermt2vard256_maskz",
+    "llvm.x86.avx512.maskz.vpermt2var.d.512" => "__builtin_ia32_vpermt2vard512_maskz",
+    "llvm.x86.avx512.maskz.vpermt2var.hi.128" => "__builtin_ia32_vpermt2varhi128_maskz",
+    "llvm.x86.avx512.maskz.vpermt2var.hi.256" => "__builtin_ia32_vpermt2varhi256_maskz",
+    "llvm.x86.avx512.maskz.vpermt2var.hi.512" => "__builtin_ia32_vpermt2varhi512_maskz",
+    "llvm.x86.avx512.maskz.vpermt2var.pd.128" => "__builtin_ia32_vpermt2varpd128_maskz",
+    "llvm.x86.avx512.maskz.vpermt2var.pd.256" => "__builtin_ia32_vpermt2varpd256_maskz",
+    "llvm.x86.avx512.maskz.vpermt2var.pd.512" => "__builtin_ia32_vpermt2varpd512_maskz",
+    "llvm.x86.avx512.maskz.vpermt2var.ps.128" => "__builtin_ia32_vpermt2varps128_maskz",
+    "llvm.x86.avx512.maskz.vpermt2var.ps.256" => "__builtin_ia32_vpermt2varps256_maskz",
+    "llvm.x86.avx512.maskz.vpermt2var.ps.512" => "__builtin_ia32_vpermt2varps512_maskz",
+    "llvm.x86.avx512.maskz.vpermt2var.q.128" => "__builtin_ia32_vpermt2varq128_maskz",
+    "llvm.x86.avx512.maskz.vpermt2var.q.256" => "__builtin_ia32_vpermt2varq256_maskz",
+    "llvm.x86.avx512.maskz.vpermt2var.q.512" => "__builtin_ia32_vpermt2varq512_maskz",
+    "llvm.x86.avx512.maskz.vpermt2var.qi.128" => "__builtin_ia32_vpermt2varqi128_maskz",
+    "llvm.x86.avx512.maskz.vpermt2var.qi.256" => "__builtin_ia32_vpermt2varqi256_maskz",
+    "llvm.x86.avx512.maskz.vpermt2var.qi.512" => "__builtin_ia32_vpermt2varqi512_maskz",
+    "llvm.x86.avx512.maskz.vpmadd52h.uq.128" => "__builtin_ia32_vpmadd52huq128_maskz",
+    "llvm.x86.avx512.maskz.vpmadd52h.uq.256" => "__builtin_ia32_vpmadd52huq256_maskz",
+    "llvm.x86.avx512.maskz.vpmadd52h.uq.512" => "__builtin_ia32_vpmadd52huq512_maskz",
+    "llvm.x86.avx512.maskz.vpmadd52l.uq.128" => "__builtin_ia32_vpmadd52luq128_maskz",
+    "llvm.x86.avx512.maskz.vpmadd52l.uq.256" => "__builtin_ia32_vpmadd52luq256_maskz",
+    "llvm.x86.avx512.maskz.vpmadd52l.uq.512" => "__builtin_ia32_vpmadd52luq512_maskz",
+    "llvm.x86.avx512.max.pd.512" => "__builtin_ia32_maxpd512",
+    "llvm.x86.avx512.max.ps.512" => "__builtin_ia32_maxps512",
+    "llvm.x86.avx512.min.pd.512" => "__builtin_ia32_minpd512",
+    "llvm.x86.avx512.min.ps.512" => "__builtin_ia32_minps512",
+    "llvm.x86.avx512.movntdqa" => "__builtin_ia32_movntdqa512",
+    "llvm.x86.avx512.mul.pd.512" => "__builtin_ia32_mulpd512",
+    "llvm.x86.avx512.mul.ps.512" => "__builtin_ia32_mulps512",
+    "llvm.x86.avx512.packssdw.512" => "__builtin_ia32_packssdw512",
+    "llvm.x86.avx512.packsswb.512" => "__builtin_ia32_packsswb512",
+    "llvm.x86.avx512.packusdw.512" => "__builtin_ia32_packusdw512",
+    "llvm.x86.avx512.packuswb.512" => "__builtin_ia32_packuswb512",
+    "llvm.x86.avx512.pavg.b.512" => "__builtin_ia32_pavgb512",
+    "llvm.x86.avx512.pavg.w.512" => "__builtin_ia32_pavgw512",
+    "llvm.x86.avx512.pbroadcastd.512" => "__builtin_ia32_pbroadcastd512",
+    "llvm.x86.avx512.pbroadcastq.512" => "__builtin_ia32_pbroadcastq512",
+    "llvm.x86.avx512.permvar.df.256" => "__builtin_ia32_permvardf256",
+    "llvm.x86.avx512.permvar.df.512" => "__builtin_ia32_permvardf512",
+    "llvm.x86.avx512.permvar.di.256" => "__builtin_ia32_permvardi256",
+    "llvm.x86.avx512.permvar.di.512" => "__builtin_ia32_permvardi512",
+    "llvm.x86.avx512.permvar.hi.128" => "__builtin_ia32_permvarhi128",
+    "llvm.x86.avx512.permvar.hi.256" => "__builtin_ia32_permvarhi256",
+    "llvm.x86.avx512.permvar.hi.512" => "__builtin_ia32_permvarhi512",
+    "llvm.x86.avx512.permvar.qi.128" => "__builtin_ia32_permvarqi128",
+    "llvm.x86.avx512.permvar.qi.256" => "__builtin_ia32_permvarqi256",
+    "llvm.x86.avx512.permvar.qi.512" => "__builtin_ia32_permvarqi512",
+    "llvm.x86.avx512.permvar.sf.512" => "__builtin_ia32_permvarsf512",
+    "llvm.x86.avx512.permvar.si.512" => "__builtin_ia32_permvarsi512",
+    "llvm.x86.avx512.pmaddubs.w.512" => "__builtin_ia32_pmaddubsw512",
+    "llvm.x86.avx512.pmaddw.d.512" => "__builtin_ia32_pmaddwd512",
+    "llvm.x86.avx512.pmovzxbd" => "__builtin_ia32_pmovzxbd512",
+    "llvm.x86.avx512.pmovzxbq" => "__builtin_ia32_pmovzxbq512",
+    "llvm.x86.avx512.pmovzxdq" => "__builtin_ia32_pmovzxdq512",
+    "llvm.x86.avx512.pmovzxwd" => "__builtin_ia32_pmovzxwd512",
+    "llvm.x86.avx512.pmovzxwq" => "__builtin_ia32_pmovzxwq512",
+    "llvm.x86.avx512.pmul.hr.sw.512" => "__builtin_ia32_pmulhrsw512",
+    "llvm.x86.avx512.pmulh.w.512" => "__builtin_ia32_pmulhw512",
+    "llvm.x86.avx512.pmulhu.w.512" => "__builtin_ia32_pmulhuw512",
+    "llvm.x86.avx512.pmultishift.qb.128" => "__builtin_ia32_vpmultishiftqb128",
+    "llvm.x86.avx512.pmultishift.qb.256" => "__builtin_ia32_vpmultishiftqb256",
+    "llvm.x86.avx512.pmultishift.qb.512" => "__builtin_ia32_vpmultishiftqb512",
+    "llvm.x86.avx512.psad.bw.512" => "__builtin_ia32_psadbw512",
+    "llvm.x86.avx512.pshuf.b.512" => "__builtin_ia32_pshufb512",
+    "llvm.x86.avx512.psll.d.512" => "__builtin_ia32_pslld512",
+    "llvm.x86.avx512.psll.dq" => "__builtin_ia32_pslldqi512",
+    "llvm.x86.avx512.psll.dq.bs" => "__builtin_ia32_pslldqi512_byteshift",
+    "llvm.x86.avx512.psll.q.512" => "__builtin_ia32_psllq512",
+    "llvm.x86.avx512.psll.w.512" => "__builtin_ia32_psllw512",
+    "llvm.x86.avx512.pslli.d.512" => "__builtin_ia32_pslldi512",
+    "llvm.x86.avx512.pslli.q.512" => "__builtin_ia32_psllqi512",
+    "llvm.x86.avx512.pslli.w.512" => "__builtin_ia32_psllwi512",
+    "llvm.x86.avx512.psllv.d.512" => "__builtin_ia32_psllv16si",
+    "llvm.x86.avx512.psllv.q.512" => "__builtin_ia32_psllv8di",
+    "llvm.x86.avx512.psllv.w.128" => "__builtin_ia32_psllv8hi",
+    "llvm.x86.avx512.psllv.w.256" => "__builtin_ia32_psllv16hi",
+    "llvm.x86.avx512.psllv.w.512" => "__builtin_ia32_psllv32hi",
+    "llvm.x86.avx512.psra.d.512" => "__builtin_ia32_psrad512",
+    "llvm.x86.avx512.psra.q.128" => "__builtin_ia32_psraq128",
+    "llvm.x86.avx512.psra.q.256" => "__builtin_ia32_psraq256",
+    "llvm.x86.avx512.psra.q.512" => "__builtin_ia32_psraq512",
+    "llvm.x86.avx512.psra.w.512" => "__builtin_ia32_psraw512",
+    "llvm.x86.avx512.psrai.d.512" => "__builtin_ia32_psradi512",
+    "llvm.x86.avx512.psrai.q.128" => "__builtin_ia32_psraqi128",
+    "llvm.x86.avx512.psrai.q.256" => "__builtin_ia32_psraqi256",
+    "llvm.x86.avx512.psrai.q.512" => "__builtin_ia32_psraqi512",
+    "llvm.x86.avx512.psrai.w.512" => "__builtin_ia32_psrawi512",
+    "llvm.x86.avx512.psrav.d.512" => "__builtin_ia32_psrav16si",
+    "llvm.x86.avx512.psrav.q.128" => "__builtin_ia32_psravq128",
+    "llvm.x86.avx512.psrav.q.256" => "__builtin_ia32_psravq256",
+    "llvm.x86.avx512.psrav.q.512" => "__builtin_ia32_psrav8di",
+    "llvm.x86.avx512.psrav.w.128" => "__builtin_ia32_psrav8hi",
+    "llvm.x86.avx512.psrav.w.256" => "__builtin_ia32_psrav16hi",
+    "llvm.x86.avx512.psrav.w.512" => "__builtin_ia32_psrav32hi",
+    "llvm.x86.avx512.psrl.d.512" => "__builtin_ia32_psrld512",
+    "llvm.x86.avx512.psrl.dq" => "__builtin_ia32_psrldqi512",
+    "llvm.x86.avx512.psrl.dq.bs" => "__builtin_ia32_psrldqi512_byteshift",
+    "llvm.x86.avx512.psrl.q.512" => "__builtin_ia32_psrlq512",
+    "llvm.x86.avx512.psrl.w.512" => "__builtin_ia32_psrlw512",
+    "llvm.x86.avx512.psrli.d.512" => "__builtin_ia32_psrldi512",
+    "llvm.x86.avx512.psrli.q.512" => "__builtin_ia32_psrlqi512",
+    "llvm.x86.avx512.psrli.w.512" => "__builtin_ia32_psrlwi512",
+    "llvm.x86.avx512.psrlv.d.512" => "__builtin_ia32_psrlv16si",
+    "llvm.x86.avx512.psrlv.q.512" => "__builtin_ia32_psrlv8di",
+    "llvm.x86.avx512.psrlv.w.128" => "__builtin_ia32_psrlv8hi",
+    "llvm.x86.avx512.psrlv.w.256" => "__builtin_ia32_psrlv16hi",
+    "llvm.x86.avx512.psrlv.w.512" => "__builtin_ia32_psrlv32hi",
+    "llvm.x86.avx512.pternlog.d.128" => "__builtin_ia32_pternlogd128",
+    "llvm.x86.avx512.pternlog.d.256" => "__builtin_ia32_pternlogd256",
+    "llvm.x86.avx512.pternlog.d.512" => "__builtin_ia32_pternlogd512",
+    "llvm.x86.avx512.pternlog.q.128" => "__builtin_ia32_pternlogq128",
+    "llvm.x86.avx512.pternlog.q.256" => "__builtin_ia32_pternlogq256",
+    "llvm.x86.avx512.pternlog.q.512" => "__builtin_ia32_pternlogq512",
+    "llvm.x86.avx512.ptestm.b.128" => "__builtin_ia32_ptestmb128",
+    "llvm.x86.avx512.ptestm.b.256" => "__builtin_ia32_ptestmb256",
+    "llvm.x86.avx512.ptestm.b.512" => "__builtin_ia32_ptestmb512",
+    "llvm.x86.avx512.ptestm.d.128" => "__builtin_ia32_ptestmd128",
+    "llvm.x86.avx512.ptestm.d.256" => "__builtin_ia32_ptestmd256",
+    "llvm.x86.avx512.ptestm.d.512" => "__builtin_ia32_ptestmd512",
+    "llvm.x86.avx512.ptestm.q.128" => "__builtin_ia32_ptestmq128",
+    "llvm.x86.avx512.ptestm.q.256" => "__builtin_ia32_ptestmq256",
+    "llvm.x86.avx512.ptestm.q.512" => "__builtin_ia32_ptestmq512",
+    "llvm.x86.avx512.ptestm.w.128" => "__builtin_ia32_ptestmw128",
+    "llvm.x86.avx512.ptestm.w.256" => "__builtin_ia32_ptestmw256",
+    "llvm.x86.avx512.ptestm.w.512" => "__builtin_ia32_ptestmw512",
+    "llvm.x86.avx512.ptestnm.b.128" => "__builtin_ia32_ptestnmb128",
+    "llvm.x86.avx512.ptestnm.b.256" => "__builtin_ia32_ptestnmb256",
+    "llvm.x86.avx512.ptestnm.b.512" => "__builtin_ia32_ptestnmb512",
+    "llvm.x86.avx512.ptestnm.d.128" => "__builtin_ia32_ptestnmd128",
+    "llvm.x86.avx512.ptestnm.d.256" => "__builtin_ia32_ptestnmd256",
+    "llvm.x86.avx512.ptestnm.d.512" => "__builtin_ia32_ptestnmd512",
+    "llvm.x86.avx512.ptestnm.q.128" => "__builtin_ia32_ptestnmq128",
+    "llvm.x86.avx512.ptestnm.q.256" => "__builtin_ia32_ptestnmq256",
+    "llvm.x86.avx512.ptestnm.q.512" => "__builtin_ia32_ptestnmq512",
+    "llvm.x86.avx512.ptestnm.w.128" => "__builtin_ia32_ptestnmw128",
+    "llvm.x86.avx512.ptestnm.w.256" => "__builtin_ia32_ptestnmw256",
+    "llvm.x86.avx512.ptestnm.w.512" => "__builtin_ia32_ptestnmw512",
+    "llvm.x86.avx512.rcp14.pd.128" => "__builtin_ia32_rcp14pd128_mask",
+    "llvm.x86.avx512.rcp14.pd.256" => "__builtin_ia32_rcp14pd256_mask",
+    "llvm.x86.avx512.rcp14.pd.512" => "__builtin_ia32_rcp14pd512_mask",
+    "llvm.x86.avx512.rcp14.ps.128" => "__builtin_ia32_rcp14ps128_mask",
+    "llvm.x86.avx512.rcp14.ps.256" => "__builtin_ia32_rcp14ps256_mask",
+    "llvm.x86.avx512.rcp14.ps.512" => "__builtin_ia32_rcp14ps512_mask",
+    "llvm.x86.avx512.rcp14.sd" => "__builtin_ia32_rcp14sd_mask",
+    "llvm.x86.avx512.rcp14.ss" => "__builtin_ia32_rcp14ss_mask",
+    "llvm.x86.avx512.rcp28.pd" => "__builtin_ia32_rcp28pd_mask",
+    "llvm.x86.avx512.rcp28.ps" => "__builtin_ia32_rcp28ps_mask",
+    "llvm.x86.avx512.rcp28.sd" => "__builtin_ia32_rcp28sd_round_mask",
+    // [DUPLICATE]: "llvm.x86.avx512.rcp28.sd" => "__builtin_ia32_rcp28sd_mask",
+    "llvm.x86.avx512.rcp28.ss" => "__builtin_ia32_rcp28ss_round_mask",
+    // [DUPLICATE]: "llvm.x86.avx512.rcp28.ss" => "__builtin_ia32_rcp28ss_mask",
+    "llvm.x86.avx512.rndscale.sd" => "__builtin_ia32_rndscalesd",
+    "llvm.x86.avx512.rndscale.ss" => "__builtin_ia32_rndscaless",
+    "llvm.x86.avx512.rsqrt14.pd.128" => "__builtin_ia32_rsqrt14pd128_mask",
+    "llvm.x86.avx512.rsqrt14.pd.256" => "__builtin_ia32_rsqrt14pd256_mask",
+    "llvm.x86.avx512.rsqrt14.pd.512" => "__builtin_ia32_rsqrt14pd512_mask",
+    "llvm.x86.avx512.rsqrt14.ps.128" => "__builtin_ia32_rsqrt14ps128_mask",
+    "llvm.x86.avx512.rsqrt14.ps.256" => "__builtin_ia32_rsqrt14ps256_mask",
+    "llvm.x86.avx512.rsqrt14.ps.512" => "__builtin_ia32_rsqrt14ps512_mask",
+    "llvm.x86.avx512.rsqrt14.sd" => "__builtin_ia32_rsqrt14sd_mask",
+    "llvm.x86.avx512.rsqrt14.ss" => "__builtin_ia32_rsqrt14ss_mask",
+    "llvm.x86.avx512.rsqrt28.pd" => "__builtin_ia32_rsqrt28pd_mask",
+    "llvm.x86.avx512.rsqrt28.ps" => "__builtin_ia32_rsqrt28ps_mask",
+    "llvm.x86.avx512.rsqrt28.sd" => "__builtin_ia32_rsqrt28sd_round_mask",
+    // [DUPLICATE]: "llvm.x86.avx512.rsqrt28.sd" => "__builtin_ia32_rsqrt28sd_mask",
+    "llvm.x86.avx512.rsqrt28.ss" => "__builtin_ia32_rsqrt28ss_round_mask",
+    // [DUPLICATE]: "llvm.x86.avx512.rsqrt28.ss" => "__builtin_ia32_rsqrt28ss_mask",
+    "llvm.x86.avx512.scatter.dpd.512" => "__builtin_ia32_scattersiv8df",
+    "llvm.x86.avx512.scatter.dpi.512" => "__builtin_ia32_scattersiv16si",
+    "llvm.x86.avx512.scatter.dpq.512" => "__builtin_ia32_scattersiv8di",
+    "llvm.x86.avx512.scatter.dps.512" => "__builtin_ia32_scattersiv16sf",
+    "llvm.x86.avx512.scatter.qpd.512" => "__builtin_ia32_scatterdiv8df",
+    "llvm.x86.avx512.scatter.qpi.512" => "__builtin_ia32_scatterdiv16si",
+    "llvm.x86.avx512.scatter.qpq.512" => "__builtin_ia32_scatterdiv8di",
+    "llvm.x86.avx512.scatter.qps.512" => "__builtin_ia32_scatterdiv16sf",
+    "llvm.x86.avx512.scatterdiv2.df" => "__builtin_ia32_scatterdiv2df",
+    "llvm.x86.avx512.scatterdiv2.di" => "__builtin_ia32_scatterdiv2di",
+    "llvm.x86.avx512.scatterdiv4.df" => "__builtin_ia32_scatterdiv4df",
+    "llvm.x86.avx512.scatterdiv4.di" => "__builtin_ia32_scatterdiv4di",
+    "llvm.x86.avx512.scatterdiv4.sf" => "__builtin_ia32_scatterdiv4sf",
+    "llvm.x86.avx512.scatterdiv4.si" => "__builtin_ia32_scatterdiv4si",
+    "llvm.x86.avx512.scatterdiv8.sf" => "__builtin_ia32_scatterdiv8sf",
+    "llvm.x86.avx512.scatterdiv8.si" => "__builtin_ia32_scatterdiv8si",
+    "llvm.x86.avx512.scatterpf.dpd.512" => "__builtin_ia32_scatterpfdpd",
+    "llvm.x86.avx512.scatterpf.dps.512" => "__builtin_ia32_scatterpfdps",
+    "llvm.x86.avx512.scatterpf.qpd.512" => "__builtin_ia32_scatterpfqpd",
+    "llvm.x86.avx512.scatterpf.qps.512" => "__builtin_ia32_scatterpfqps",
+    "llvm.x86.avx512.scattersiv2.df" => "__builtin_ia32_scattersiv2df",
+    "llvm.x86.avx512.scattersiv2.di" => "__builtin_ia32_scattersiv2di",
+    "llvm.x86.avx512.scattersiv4.df" => "__builtin_ia32_scattersiv4df",
+    "llvm.x86.avx512.scattersiv4.di" => "__builtin_ia32_scattersiv4di",
+    "llvm.x86.avx512.scattersiv4.sf" => "__builtin_ia32_scattersiv4sf",
+    "llvm.x86.avx512.scattersiv4.si" => "__builtin_ia32_scattersiv4si",
+    "llvm.x86.avx512.scattersiv8.sf" => "__builtin_ia32_scattersiv8sf",
+    "llvm.x86.avx512.scattersiv8.si" => "__builtin_ia32_scattersiv8si",
+    "llvm.x86.avx512.sqrt.pd.512" => "__builtin_ia32_sqrtpd512_mask",
+    "llvm.x86.avx512.sqrt.ps.512" => "__builtin_ia32_sqrtps512_mask",
+    "llvm.x86.avx512.sqrt.sd" => "__builtin_ia32_sqrtrndsd",
+    "llvm.x86.avx512.sqrt.ss" => "__builtin_ia32_sqrtrndss",
+    "llvm.x86.avx512.sub.pd.512" => "__builtin_ia32_subpd512",
+    "llvm.x86.avx512.sub.ps.512" => "__builtin_ia32_subps512",
+    "llvm.x86.avx512.vbroadcast.sd.512" => "__builtin_ia32_vbroadcastsd512",
+    "llvm.x86.avx512.vbroadcast.sd.pd.512" => "__builtin_ia32_vbroadcastsd_pd512",
+    "llvm.x86.avx512.vbroadcast.ss.512" => "__builtin_ia32_vbroadcastss512",
+    "llvm.x86.avx512.vbroadcast.ss.ps.512" => "__builtin_ia32_vbroadcastss_ps512",
+    "llvm.x86.avx512.vcomi.sd" => "__builtin_ia32_vcomisd",
+    "llvm.x86.avx512.vcomi.ss" => "__builtin_ia32_vcomiss",
+    "llvm.x86.avx512.vcvtsd2si32" => "__builtin_ia32_vcvtsd2si32",
+    "llvm.x86.avx512.vcvtsd2si64" => "__builtin_ia32_vcvtsd2si64",
+    "llvm.x86.avx512.vcvtsd2usi32" => "__builtin_ia32_vcvtsd2usi32",
+    "llvm.x86.avx512.vcvtsd2usi64" => "__builtin_ia32_vcvtsd2usi64",
+    "llvm.x86.avx512.vcvtss2si32" => "__builtin_ia32_vcvtss2si32",
+    "llvm.x86.avx512.vcvtss2si64" => "__builtin_ia32_vcvtss2si64",
+    "llvm.x86.avx512.vcvtss2usi32" => "__builtin_ia32_vcvtss2usi32",
+    "llvm.x86.avx512.vcvtss2usi64" => "__builtin_ia32_vcvtss2usi64",
+    "llvm.x86.avx512.vpdpbusd.128" => "__builtin_ia32_vpdpbusd128",
+    "llvm.x86.avx512.vpdpbusd.256" => "__builtin_ia32_vpdpbusd256",
+    "llvm.x86.avx512.vpdpbusd.512" => "__builtin_ia32_vpdpbusd512",
+    "llvm.x86.avx512.vpdpbusds.128" => "__builtin_ia32_vpdpbusds128",
+    "llvm.x86.avx512.vpdpbusds.256" => "__builtin_ia32_vpdpbusds256",
+    "llvm.x86.avx512.vpdpbusds.512" => "__builtin_ia32_vpdpbusds512",
+    "llvm.x86.avx512.vpdpwssd.128" => "__builtin_ia32_vpdpwssd128",
+    "llvm.x86.avx512.vpdpwssd.256" => "__builtin_ia32_vpdpwssd256",
+    "llvm.x86.avx512.vpdpwssd.512" => "__builtin_ia32_vpdpwssd512",
+    "llvm.x86.avx512.vpdpwssds.128" => "__builtin_ia32_vpdpwssds128",
+    "llvm.x86.avx512.vpdpwssds.256" => "__builtin_ia32_vpdpwssds256",
+    "llvm.x86.avx512.vpdpwssds.512" => "__builtin_ia32_vpdpwssds512",
+    "llvm.x86.avx512.vpermi2var.d.128" => "__builtin_ia32_vpermi2vard128",
+    "llvm.x86.avx512.vpermi2var.d.256" => "__builtin_ia32_vpermi2vard256",
+    "llvm.x86.avx512.vpermi2var.d.512" => "__builtin_ia32_vpermi2vard512",
+    "llvm.x86.avx512.vpermi2var.hi.128" => "__builtin_ia32_vpermi2varhi128",
+    "llvm.x86.avx512.vpermi2var.hi.256" => "__builtin_ia32_vpermi2varhi256",
+    "llvm.x86.avx512.vpermi2var.hi.512" => "__builtin_ia32_vpermi2varhi512",
+    "llvm.x86.avx512.vpermi2var.pd.128" => "__builtin_ia32_vpermi2varpd128",
+    "llvm.x86.avx512.vpermi2var.pd.256" => "__builtin_ia32_vpermi2varpd256",
+    "llvm.x86.avx512.vpermi2var.pd.512" => "__builtin_ia32_vpermi2varpd512",
+    "llvm.x86.avx512.vpermi2var.ps.128" => "__builtin_ia32_vpermi2varps128",
+    "llvm.x86.avx512.vpermi2var.ps.256" => "__builtin_ia32_vpermi2varps256",
+    "llvm.x86.avx512.vpermi2var.ps.512" => "__builtin_ia32_vpermi2varps512",
+    "llvm.x86.avx512.vpermi2var.q.128" => "__builtin_ia32_vpermi2varq128",
+    "llvm.x86.avx512.vpermi2var.q.256" => "__builtin_ia32_vpermi2varq256",
+    "llvm.x86.avx512.vpermi2var.q.512" => "__builtin_ia32_vpermi2varq512",
+    "llvm.x86.avx512.vpermi2var.qi.128" => "__builtin_ia32_vpermi2varqi128",
+    "llvm.x86.avx512.vpermi2var.qi.256" => "__builtin_ia32_vpermi2varqi256",
+    "llvm.x86.avx512.vpermi2var.qi.512" => "__builtin_ia32_vpermi2varqi512",
+    "llvm.x86.avx512.vpermilvar.pd.512" => "__builtin_ia32_vpermilvarpd512",
+    "llvm.x86.avx512.vpermilvar.ps.512" => "__builtin_ia32_vpermilvarps512",
+    "llvm.x86.avx512.vpmadd52h.uq.128" => "__builtin_ia32_vpmadd52huq128",
+    "llvm.x86.avx512.vpmadd52h.uq.256" => "__builtin_ia32_vpmadd52huq256",
+    "llvm.x86.avx512.vpmadd52h.uq.512" => "__builtin_ia32_vpmadd52huq512",
+    "llvm.x86.avx512.vpmadd52l.uq.128" => "__builtin_ia32_vpmadd52luq128",
+    "llvm.x86.avx512.vpmadd52l.uq.256" => "__builtin_ia32_vpmadd52luq256",
+    "llvm.x86.avx512.vpmadd52l.uq.512" => "__builtin_ia32_vpmadd52luq512",
+    "llvm.x86.avx512bf16.cvtne2ps2bf16.128" => "__builtin_ia32_cvtne2ps2bf16_128",
+    "llvm.x86.avx512bf16.cvtne2ps2bf16.256" => "__builtin_ia32_cvtne2ps2bf16_256",
+    "llvm.x86.avx512bf16.cvtne2ps2bf16.512" => "__builtin_ia32_cvtne2ps2bf16_512",
+    "llvm.x86.avx512bf16.cvtneps2bf16.256" => "__builtin_ia32_cvtneps2bf16_256",
+    "llvm.x86.avx512bf16.cvtneps2bf16.512" => "__builtin_ia32_cvtneps2bf16_512",
+    "llvm.x86.avx512bf16.dpbf16ps.128" => "__builtin_ia32_dpbf16ps_128",
+    "llvm.x86.avx512bf16.dpbf16ps.256" => "__builtin_ia32_dpbf16ps_256",
+    "llvm.x86.avx512bf16.dpbf16ps.512" => "__builtin_ia32_dpbf16ps_512",
+    "llvm.x86.avx512fp16.add.ph.512" => "__builtin_ia32_addph512",
+    "llvm.x86.avx512fp16.div.ph.512" => "__builtin_ia32_divph512",
+    "llvm.x86.avx512fp16.mask.add.sh.round" => "__builtin_ia32_addsh_round_mask",
+    "llvm.x86.avx512fp16.mask.cmp.sh" => "__builtin_ia32_cmpsh_mask",
+    "llvm.x86.avx512fp16.mask.div.sh.round" => "__builtin_ia32_divsh_round_mask",
+    "llvm.x86.avx512fp16.mask.fpclass.sh" => "__builtin_ia32_fpclasssh_mask",
+    "llvm.x86.avx512fp16.mask.getexp.ph.128" => "__builtin_ia32_getexpph128_mask",
+    "llvm.x86.avx512fp16.mask.getexp.ph.256" => "__builtin_ia32_getexpph256_mask",
+    "llvm.x86.avx512fp16.mask.getexp.ph.512" => "__builtin_ia32_getexpph512_mask",
+    "llvm.x86.avx512fp16.mask.getexp.sh" => "__builtin_ia32_getexpsh128_round_mask",
+    "llvm.x86.avx512fp16.mask.getmant.ph.128" => "__builtin_ia32_getmantph128_mask",
+    "llvm.x86.avx512fp16.mask.getmant.ph.256" => "__builtin_ia32_getmantph256_mask",
+    "llvm.x86.avx512fp16.mask.getmant.ph.512" => "__builtin_ia32_getmantph512_mask",
+    "llvm.x86.avx512fp16.mask.getmant.sh" => "__builtin_ia32_getmantsh_round_mask",
+    "llvm.x86.avx512fp16.mask.max.sh.round" => "__builtin_ia32_maxsh_round_mask",
+    "llvm.x86.avx512fp16.mask.min.sh.round" => "__builtin_ia32_minsh_round_mask",
+    "llvm.x86.avx512fp16.mask.mul.sh.round" => "__builtin_ia32_mulsh_round_mask",
+    "llvm.x86.avx512fp16.mask.rcp.ph.128" => "__builtin_ia32_rcpph128_mask",
+    "llvm.x86.avx512fp16.mask.rcp.ph.256" => "__builtin_ia32_rcpph256_mask",
+    "llvm.x86.avx512fp16.mask.rcp.ph.512" => "__builtin_ia32_rcpph512_mask",
+    "llvm.x86.avx512fp16.mask.rcp.sh" => "__builtin_ia32_rcpsh_mask",
+    "llvm.x86.avx512fp16.mask.reduce.ph.128" => "__builtin_ia32_reduceph128_mask",
+    "llvm.x86.avx512fp16.mask.reduce.ph.256" => "__builtin_ia32_reduceph256_mask",
+    "llvm.x86.avx512fp16.mask.reduce.ph.512" => "__builtin_ia32_reduceph512_mask",
+    "llvm.x86.avx512fp16.mask.reduce.sh" => "__builtin_ia32_reducesh_mask",
+    "llvm.x86.avx512fp16.mask.rndscale.ph.128" => "__builtin_ia32_rndscaleph_128_mask",
+    "llvm.x86.avx512fp16.mask.rndscale.ph.256" => "__builtin_ia32_rndscaleph_256_mask",
+    "llvm.x86.avx512fp16.mask.rndscale.ph.512" => "__builtin_ia32_rndscaleph_mask",
+    "llvm.x86.avx512fp16.mask.rndscale.sh" => "__builtin_ia32_rndscalesh_round_mask",
+    "llvm.x86.avx512fp16.mask.rsqrt.ph.128" => "__builtin_ia32_rsqrtph128_mask",
+    "llvm.x86.avx512fp16.mask.rsqrt.ph.256" => "__builtin_ia32_rsqrtph256_mask",
+    "llvm.x86.avx512fp16.mask.rsqrt.ph.512" => "__builtin_ia32_rsqrtph512_mask",
+    "llvm.x86.avx512fp16.mask.rsqrt.sh" => "__builtin_ia32_rsqrtsh_mask",
+    "llvm.x86.avx512fp16.mask.scalef.ph.128" => "__builtin_ia32_scalefph128_mask",
+    "llvm.x86.avx512fp16.mask.scalef.ph.256" => "__builtin_ia32_scalefph256_mask",
+    "llvm.x86.avx512fp16.mask.scalef.ph.512" => "__builtin_ia32_scalefph512_mask",
+    "llvm.x86.avx512fp16.mask.scalef.sh" => "__builtin_ia32_scalefsh_round_mask",
+    "llvm.x86.avx512fp16.mask.sub.sh.round" => "__builtin_ia32_subsh_round_mask",
+    "llvm.x86.avx512fp16.mask.vcvtdq2ph.128" => "__builtin_ia32_vcvtdq2ph128_mask",
+    "llvm.x86.avx512fp16.mask.vcvtpd2ph.128" => "__builtin_ia32_vcvtpd2ph128_mask",
+    "llvm.x86.avx512fp16.mask.vcvtpd2ph.256" => "__builtin_ia32_vcvtpd2ph256_mask",
+    "llvm.x86.avx512fp16.mask.vcvtpd2ph.512" => "__builtin_ia32_vcvtpd2ph512_mask",
+    "llvm.x86.avx512fp16.mask.vcvtph2dq.128" => "__builtin_ia32_vcvtph2dq128_mask",
+    "llvm.x86.avx512fp16.mask.vcvtph2dq.256" => "__builtin_ia32_vcvtph2dq256_mask",
+    "llvm.x86.avx512fp16.mask.vcvtph2dq.512" => "__builtin_ia32_vcvtph2dq512_mask",
+    "llvm.x86.avx512fp16.mask.vcvtph2pd.128" => "__builtin_ia32_vcvtph2pd128_mask",
+    "llvm.x86.avx512fp16.mask.vcvtph2pd.256" => "__builtin_ia32_vcvtph2pd256_mask",
+    "llvm.x86.avx512fp16.mask.vcvtph2pd.512" => "__builtin_ia32_vcvtph2pd512_mask",
+    "llvm.x86.avx512fp16.mask.vcvtph2psx.128" => "__builtin_ia32_vcvtph2psx128_mask",
+    "llvm.x86.avx512fp16.mask.vcvtph2psx.256" => "__builtin_ia32_vcvtph2psx256_mask",
+    "llvm.x86.avx512fp16.mask.vcvtph2psx.512" => "__builtin_ia32_vcvtph2psx512_mask",
+    "llvm.x86.avx512fp16.mask.vcvtph2qq.128" => "__builtin_ia32_vcvtph2qq128_mask",
+    "llvm.x86.avx512fp16.mask.vcvtph2qq.256" => "__builtin_ia32_vcvtph2qq256_mask",
+    "llvm.x86.avx512fp16.mask.vcvtph2qq.512" => "__builtin_ia32_vcvtph2qq512_mask",
+    "llvm.x86.avx512fp16.mask.vcvtph2udq.128" => "__builtin_ia32_vcvtph2udq128_mask",
+    "llvm.x86.avx512fp16.mask.vcvtph2udq.256" => "__builtin_ia32_vcvtph2udq256_mask",
+    "llvm.x86.avx512fp16.mask.vcvtph2udq.512" => "__builtin_ia32_vcvtph2udq512_mask",
+    "llvm.x86.avx512fp16.mask.vcvtph2uqq.128" => "__builtin_ia32_vcvtph2uqq128_mask",
+    "llvm.x86.avx512fp16.mask.vcvtph2uqq.256" => "__builtin_ia32_vcvtph2uqq256_mask",
+    "llvm.x86.avx512fp16.mask.vcvtph2uqq.512" => "__builtin_ia32_vcvtph2uqq512_mask",
+    "llvm.x86.avx512fp16.mask.vcvtph2uw.128" => "__builtin_ia32_vcvtph2uw128_mask",
+    "llvm.x86.avx512fp16.mask.vcvtph2uw.256" => "__builtin_ia32_vcvtph2uw256_mask",
+    "llvm.x86.avx512fp16.mask.vcvtph2uw.512" => "__builtin_ia32_vcvtph2uw512_mask",
+    "llvm.x86.avx512fp16.mask.vcvtph2w.128" => "__builtin_ia32_vcvtph2w128_mask",
+    "llvm.x86.avx512fp16.mask.vcvtph2w.256" => "__builtin_ia32_vcvtph2w256_mask",
+    "llvm.x86.avx512fp16.mask.vcvtph2w.512" => "__builtin_ia32_vcvtph2w512_mask",
+    "llvm.x86.avx512fp16.mask.vcvtps2phx.128" => "__builtin_ia32_vcvtps2phx128_mask",
+    "llvm.x86.avx512fp16.mask.vcvtps2phx.256" => "__builtin_ia32_vcvtps2phx256_mask",
+    "llvm.x86.avx512fp16.mask.vcvtps2phx.512" => "__builtin_ia32_vcvtps2phx512_mask",
+    "llvm.x86.avx512fp16.mask.vcvtqq2ph.128" => "__builtin_ia32_vcvtqq2ph128_mask",
+    "llvm.x86.avx512fp16.mask.vcvtqq2ph.256" => "__builtin_ia32_vcvtqq2ph256_mask",
+    "llvm.x86.avx512fp16.mask.vcvtsd2sh.round" => "__builtin_ia32_vcvtsd2sh_round_mask",
+    "llvm.x86.avx512fp16.mask.vcvtsh2sd.round" => "__builtin_ia32_vcvtsh2sd_round_mask",
+    "llvm.x86.avx512fp16.mask.vcvtsh2ss.round" => "__builtin_ia32_vcvtsh2ss_round_mask",
+    "llvm.x86.avx512fp16.mask.vcvtss2sh.round" => "__builtin_ia32_vcvtss2sh_round_mask",
+    "llvm.x86.avx512fp16.mask.vcvttph2dq.128" => "__builtin_ia32_vcvttph2dq128_mask",
+    "llvm.x86.avx512fp16.mask.vcvttph2dq.256" => "__builtin_ia32_vcvttph2dq256_mask",
+    "llvm.x86.avx512fp16.mask.vcvttph2dq.512" => "__builtin_ia32_vcvttph2dq512_mask",
+    "llvm.x86.avx512fp16.mask.vcvttph2qq.128" => "__builtin_ia32_vcvttph2qq128_mask",
+    "llvm.x86.avx512fp16.mask.vcvttph2qq.256" => "__builtin_ia32_vcvttph2qq256_mask",
+    "llvm.x86.avx512fp16.mask.vcvttph2qq.512" => "__builtin_ia32_vcvttph2qq512_mask",
+    "llvm.x86.avx512fp16.mask.vcvttph2udq.128" => "__builtin_ia32_vcvttph2udq128_mask",
+    "llvm.x86.avx512fp16.mask.vcvttph2udq.256" => "__builtin_ia32_vcvttph2udq256_mask",
+    "llvm.x86.avx512fp16.mask.vcvttph2udq.512" => "__builtin_ia32_vcvttph2udq512_mask",
+    "llvm.x86.avx512fp16.mask.vcvttph2uqq.128" => "__builtin_ia32_vcvttph2uqq128_mask",
+    "llvm.x86.avx512fp16.mask.vcvttph2uqq.256" => "__builtin_ia32_vcvttph2uqq256_mask",
+    "llvm.x86.avx512fp16.mask.vcvttph2uqq.512" => "__builtin_ia32_vcvttph2uqq512_mask",
+    "llvm.x86.avx512fp16.mask.vcvttph2uw.128" => "__builtin_ia32_vcvttph2uw128_mask",
+    "llvm.x86.avx512fp16.mask.vcvttph2uw.256" => "__builtin_ia32_vcvttph2uw256_mask",
+    "llvm.x86.avx512fp16.mask.vcvttph2uw.512" => "__builtin_ia32_vcvttph2uw512_mask",
+    "llvm.x86.avx512fp16.mask.vcvttph2w.128" => "__builtin_ia32_vcvttph2w128_mask",
+    "llvm.x86.avx512fp16.mask.vcvttph2w.256" => "__builtin_ia32_vcvttph2w256_mask",
+    "llvm.x86.avx512fp16.mask.vcvttph2w.512" => "__builtin_ia32_vcvttph2w512_mask",
+    "llvm.x86.avx512fp16.mask.vcvtudq2ph.128" => "__builtin_ia32_vcvtudq2ph128_mask",
+    "llvm.x86.avx512fp16.mask.vcvtuqq2ph.128" => "__builtin_ia32_vcvtuqq2ph128_mask",
+    "llvm.x86.avx512fp16.mask.vcvtuqq2ph.256" => "__builtin_ia32_vcvtuqq2ph256_mask",
+    "llvm.x86.avx512fp16.mask.vfcmadd.cph.128" => "__builtin_ia32_vfcmaddcph128_mask",
+    "llvm.x86.avx512fp16.mask.vfcmadd.cph.256" => "__builtin_ia32_vfcmaddcph256_mask",
+    "llvm.x86.avx512fp16.mask.vfcmadd.cph.512" => "__builtin_ia32_vfcmaddcph512_mask3",
+    "llvm.x86.avx512fp16.mask.vfcmadd.csh" => "__builtin_ia32_vfcmaddcsh_mask",
+    "llvm.x86.avx512fp16.mask.vfcmul.cph.128" => "__builtin_ia32_vfcmulcph128_mask",
+    "llvm.x86.avx512fp16.mask.vfcmul.cph.256" => "__builtin_ia32_vfcmulcph256_mask",
+    "llvm.x86.avx512fp16.mask.vfcmul.cph.512" => "__builtin_ia32_vfcmulcph512_mask",
+    "llvm.x86.avx512fp16.mask.vfcmul.csh" => "__builtin_ia32_vfcmulcsh_mask",
+    "llvm.x86.avx512fp16.mask.vfmadd.cph.128" => "__builtin_ia32_vfmaddcph128_mask",
+    "llvm.x86.avx512fp16.mask.vfmadd.cph.256" => "__builtin_ia32_vfmaddcph256_mask",
+    "llvm.x86.avx512fp16.mask.vfmadd.cph.512" => "__builtin_ia32_vfmaddcph512_mask3",
+    "llvm.x86.avx512fp16.mask.vfmadd.csh" => "__builtin_ia32_vfmaddcsh_mask",
+    "llvm.x86.avx512fp16.mask.vfmul.cph.128" => "__builtin_ia32_vfmulcph128_mask",
+    "llvm.x86.avx512fp16.mask.vfmul.cph.256" => "__builtin_ia32_vfmulcph256_mask",
+    "llvm.x86.avx512fp16.mask.vfmul.cph.512" => "__builtin_ia32_vfmulcph512_mask",
+    "llvm.x86.avx512fp16.mask.vfmul.csh" => "__builtin_ia32_vfmulcsh_mask",
+    "llvm.x86.avx512fp16.maskz.vfcmadd.cph.128" => "__builtin_ia32_vfcmaddcph128_maskz",
+    "llvm.x86.avx512fp16.maskz.vfcmadd.cph.256" => "__builtin_ia32_vfcmaddcph256_maskz",
+    "llvm.x86.avx512fp16.maskz.vfcmadd.cph.512" => "__builtin_ia32_vfcmaddcph512_maskz",
+    "llvm.x86.avx512fp16.maskz.vfcmadd.csh" => "__builtin_ia32_vfcmaddcsh_maskz",
+    "llvm.x86.avx512fp16.maskz.vfmadd.cph.128" => "__builtin_ia32_vfmaddcph128_maskz",
+    "llvm.x86.avx512fp16.maskz.vfmadd.cph.256" => "__builtin_ia32_vfmaddcph256_maskz",
+    "llvm.x86.avx512fp16.maskz.vfmadd.cph.512" => "__builtin_ia32_vfmaddcph512_maskz",
+    "llvm.x86.avx512fp16.maskz.vfmadd.csh" => "__builtin_ia32_vfmaddcsh_maskz",
+    "llvm.x86.avx512fp16.max.ph.128" => "__builtin_ia32_maxph128",
+    "llvm.x86.avx512fp16.max.ph.256" => "__builtin_ia32_maxph256",
+    "llvm.x86.avx512fp16.max.ph.512" => "__builtin_ia32_maxph512",
+    "llvm.x86.avx512fp16.min.ph.128" => "__builtin_ia32_minph128",
+    "llvm.x86.avx512fp16.min.ph.256" => "__builtin_ia32_minph256",
+    "llvm.x86.avx512fp16.min.ph.512" => "__builtin_ia32_minph512",
+    "llvm.x86.avx512fp16.mul.ph.512" => "__builtin_ia32_mulph512",
+    "llvm.x86.avx512fp16.sub.ph.512" => "__builtin_ia32_subph512",
+    "llvm.x86.avx512fp16.vcomi.sh" => "__builtin_ia32_vcomish",
+    "llvm.x86.avx512fp16.vcvtsh2si32" => "__builtin_ia32_vcvtsh2si32",
+    "llvm.x86.avx512fp16.vcvtsh2si64" => "__builtin_ia32_vcvtsh2si64",
+    "llvm.x86.avx512fp16.vcvtsh2usi32" => "__builtin_ia32_vcvtsh2usi32",
+    "llvm.x86.avx512fp16.vcvtsh2usi64" => "__builtin_ia32_vcvtsh2usi64",
+    "llvm.x86.avx512fp16.vcvtsi2sh" => "__builtin_ia32_vcvtsi2sh",
+    "llvm.x86.avx512fp16.vcvtsi642sh" => "__builtin_ia32_vcvtsi642sh",
+    "llvm.x86.avx512fp16.vcvttsh2si32" => "__builtin_ia32_vcvttsh2si32",
+    "llvm.x86.avx512fp16.vcvttsh2si64" => "__builtin_ia32_vcvttsh2si64",
+    "llvm.x86.avx512fp16.vcvttsh2usi32" => "__builtin_ia32_vcvttsh2usi32",
+    "llvm.x86.avx512fp16.vcvttsh2usi64" => "__builtin_ia32_vcvttsh2usi64",
+    "llvm.x86.avx512fp16.vcvtusi2sh" => "__builtin_ia32_vcvtusi2sh",
+    "llvm.x86.avx512fp16.vcvtusi642sh" => "__builtin_ia32_vcvtusi642sh",
+    "llvm.x86.avx512fp16.vfmaddsub.ph.128" => "__builtin_ia32_vfmaddsubph",
+    "llvm.x86.avx512fp16.vfmaddsub.ph.256" => "__builtin_ia32_vfmaddsubph256",
+    "llvm.x86.bmi.bextr.32" => "__builtin_ia32_bextr_u32",
+    "llvm.x86.bmi.bextr.64" => "__builtin_ia32_bextr_u64",
+    "llvm.x86.bmi.bzhi.32" => "__builtin_ia32_bzhi_si",
+    "llvm.x86.bmi.bzhi.64" => "__builtin_ia32_bzhi_di",
+    "llvm.x86.bmi.pdep.32" => "__builtin_ia32_pdep_si",
+    "llvm.x86.bmi.pdep.64" => "__builtin_ia32_pdep_di",
+    "llvm.x86.bmi.pext.32" => "__builtin_ia32_pext_si",
+    "llvm.x86.bmi.pext.64" => "__builtin_ia32_pext_di",
+    "llvm.x86.cldemote" => "__builtin_ia32_cldemote",
+    "llvm.x86.clflushopt" => "__builtin_ia32_clflushopt",
+    "llvm.x86.clrssbsy" => "__builtin_ia32_clrssbsy",
+    "llvm.x86.clui" => "__builtin_ia32_clui",
+    "llvm.x86.clwb" => "__builtin_ia32_clwb",
+    "llvm.x86.clzero" => "__builtin_ia32_clzero",
+    "llvm.x86.directstore32" => "__builtin_ia32_directstore_u32",
+    "llvm.x86.directstore64" => "__builtin_ia32_directstore_u64",
+    "llvm.x86.enqcmd" => "__builtin_ia32_enqcmd",
+    "llvm.x86.enqcmds" => "__builtin_ia32_enqcmds",
+    "llvm.x86.flags.read.u32" => "__builtin_ia32_readeflags_u32",
+    "llvm.x86.flags.read.u64" => "__builtin_ia32_readeflags_u64",
+    "llvm.x86.flags.write.u32" => "__builtin_ia32_writeeflags_u32",
+    "llvm.x86.flags.write.u64" => "__builtin_ia32_writeeflags_u64",
+    "llvm.x86.fma.mask.vfmadd.pd.512" => "__builtin_ia32_vfmaddpd512_mask",
+    "llvm.x86.fma.mask.vfmadd.ps.512" => "__builtin_ia32_vfmaddps512_mask",
+    "llvm.x86.fma.mask.vfmaddsub.pd.512" => "__builtin_ia32_vfmaddsubpd512_mask",
+    "llvm.x86.fma.mask.vfmaddsub.ps.512" => "__builtin_ia32_vfmaddsubps512_mask",
+    "llvm.x86.fma.mask.vfmsub.pd.512" => "__builtin_ia32_vfmsubpd512_mask",
+    "llvm.x86.fma.mask.vfmsub.ps.512" => "__builtin_ia32_vfmsubps512_mask",
+    "llvm.x86.fma.mask.vfmsubadd.pd.512" => "__builtin_ia32_vfmsubaddpd512_mask",
+    "llvm.x86.fma.mask.vfmsubadd.ps.512" => "__builtin_ia32_vfmsubaddps512_mask",
+    "llvm.x86.fma.mask.vfnmadd.pd.512" => "__builtin_ia32_vfnmaddpd512_mask",
+    "llvm.x86.fma.mask.vfnmadd.ps.512" => "__builtin_ia32_vfnmaddps512_mask",
+    "llvm.x86.fma.mask.vfnmsub.pd.512" => "__builtin_ia32_vfnmsubpd512_mask",
+    "llvm.x86.fma.mask.vfnmsub.ps.512" => "__builtin_ia32_vfnmsubps512_mask",
+    "llvm.x86.fma.vfmadd.pd" => "__builtin_ia32_vfmaddpd",
+    "llvm.x86.fma.vfmadd.pd.256" => "__builtin_ia32_vfmaddpd256",
+    "llvm.x86.fma.vfmadd.ps" => "__builtin_ia32_vfmaddps",
+    "llvm.x86.fma.vfmadd.ps.256" => "__builtin_ia32_vfmaddps256",
+    "llvm.x86.fma.vfmadd.sd" => "__builtin_ia32_vfmaddsd",
+    "llvm.x86.fma.vfmadd.ss" => "__builtin_ia32_vfmaddss",
+    "llvm.x86.fma.vfmaddsub.pd" => "__builtin_ia32_vfmaddsubpd",
+    "llvm.x86.fma.vfmaddsub.pd.256" => "__builtin_ia32_vfmaddsubpd256",
+    "llvm.x86.fma.vfmaddsub.ps" => "__builtin_ia32_vfmaddsubps",
+    "llvm.x86.fma.vfmaddsub.ps.256" => "__builtin_ia32_vfmaddsubps256",
+    "llvm.x86.fma.vfmsub.pd" => "__builtin_ia32_vfmsubpd",
+    "llvm.x86.fma.vfmsub.pd.256" => "__builtin_ia32_vfmsubpd256",
+    "llvm.x86.fma.vfmsub.ps" => "__builtin_ia32_vfmsubps",
+    "llvm.x86.fma.vfmsub.ps.256" => "__builtin_ia32_vfmsubps256",
+    "llvm.x86.fma.vfmsub.sd" => "__builtin_ia32_vfmsubsd",
+    "llvm.x86.fma.vfmsub.ss" => "__builtin_ia32_vfmsubss",
+    "llvm.x86.fma.vfmsubadd.pd" => "__builtin_ia32_vfmsubaddpd",
+    "llvm.x86.fma.vfmsubadd.pd.256" => "__builtin_ia32_vfmsubaddpd256",
+    "llvm.x86.fma.vfmsubadd.ps" => "__builtin_ia32_vfmsubaddps",
+    "llvm.x86.fma.vfmsubadd.ps.256" => "__builtin_ia32_vfmsubaddps256",
+    "llvm.x86.fma.vfnmadd.pd" => "__builtin_ia32_vfnmaddpd",
+    "llvm.x86.fma.vfnmadd.pd.256" => "__builtin_ia32_vfnmaddpd256",
+    "llvm.x86.fma.vfnmadd.ps" => "__builtin_ia32_vfnmaddps",
+    "llvm.x86.fma.vfnmadd.ps.256" => "__builtin_ia32_vfnmaddps256",
+    "llvm.x86.fma.vfnmadd.sd" => "__builtin_ia32_vfnmaddsd",
+    "llvm.x86.fma.vfnmadd.ss" => "__builtin_ia32_vfnmaddss",
+    "llvm.x86.fma.vfnmsub.pd" => "__builtin_ia32_vfnmsubpd",
+    "llvm.x86.fma.vfnmsub.pd.256" => "__builtin_ia32_vfnmsubpd256",
+    "llvm.x86.fma.vfnmsub.ps" => "__builtin_ia32_vfnmsubps",
+    "llvm.x86.fma.vfnmsub.ps.256" => "__builtin_ia32_vfnmsubps256",
+    "llvm.x86.fma.vfnmsub.sd" => "__builtin_ia32_vfnmsubsd",
+    "llvm.x86.fma.vfnmsub.ss" => "__builtin_ia32_vfnmsubss",
+    "llvm.x86.fxrstor" => "__builtin_ia32_fxrstor",
+    "llvm.x86.fxrstor64" => "__builtin_ia32_fxrstor64",
+    "llvm.x86.fxsave" => "__builtin_ia32_fxsave",
+    "llvm.x86.fxsave64" => "__builtin_ia32_fxsave64",
+    "llvm.x86.incsspd" => "__builtin_ia32_incsspd",
+    "llvm.x86.incsspq" => "__builtin_ia32_incsspq",
+    "llvm.x86.invpcid" => "__builtin_ia32_invpcid",
+    "llvm.x86.ldtilecfg" => "__builtin_ia32_tile_loadconfig",
+    "llvm.x86.ldtilecfg.internal" => "__builtin_ia32_tile_loadconfig_internal",
+    "llvm.x86.llwpcb" => "__builtin_ia32_llwpcb",
+    "llvm.x86.loadiwkey" => "__builtin_ia32_loadiwkey",
+    "llvm.x86.lwpins32" => "__builtin_ia32_lwpins32",
+    "llvm.x86.lwpins64" => "__builtin_ia32_lwpins64",
+    "llvm.x86.lwpval32" => "__builtin_ia32_lwpval32",
+    "llvm.x86.lwpval64" => "__builtin_ia32_lwpval64",
+    "llvm.x86.mmx.emms" => "__builtin_ia32_emms",
+    "llvm.x86.mmx.femms" => "__builtin_ia32_femms",
+    "llvm.x86.mmx.maskmovq" => "__builtin_ia32_maskmovq",
+    "llvm.x86.mmx.movnt.dq" => "__builtin_ia32_movntq",
+    "llvm.x86.mmx.packssdw" => "__builtin_ia32_packssdw",
+    "llvm.x86.mmx.packsswb" => "__builtin_ia32_packsswb",
+    "llvm.x86.mmx.packuswb" => "__builtin_ia32_packuswb",
+    "llvm.x86.mmx.padd.b" => "__builtin_ia32_paddb",
+    "llvm.x86.mmx.padd.d" => "__builtin_ia32_paddd",
+    "llvm.x86.mmx.padd.q" => "__builtin_ia32_paddq",
+    "llvm.x86.mmx.padd.w" => "__builtin_ia32_paddw",
+    "llvm.x86.mmx.padds.b" => "__builtin_ia32_paddsb",
+    "llvm.x86.mmx.padds.w" => "__builtin_ia32_paddsw",
+    "llvm.x86.mmx.paddus.b" => "__builtin_ia32_paddusb",
+    "llvm.x86.mmx.paddus.w" => "__builtin_ia32_paddusw",
+    "llvm.x86.mmx.palignr.b" => "__builtin_ia32_palignr",
+    "llvm.x86.mmx.pand" => "__builtin_ia32_pand",
+    "llvm.x86.mmx.pandn" => "__builtin_ia32_pandn",
+    "llvm.x86.mmx.pavg.b" => "__builtin_ia32_pavgb",
+    "llvm.x86.mmx.pavg.w" => "__builtin_ia32_pavgw",
+    "llvm.x86.mmx.pcmpeq.b" => "__builtin_ia32_pcmpeqb",
+    "llvm.x86.mmx.pcmpeq.d" => "__builtin_ia32_pcmpeqd",
+    "llvm.x86.mmx.pcmpeq.w" => "__builtin_ia32_pcmpeqw",
+    "llvm.x86.mmx.pcmpgt.b" => "__builtin_ia32_pcmpgtb",
+    "llvm.x86.mmx.pcmpgt.d" => "__builtin_ia32_pcmpgtd",
+    "llvm.x86.mmx.pcmpgt.w" => "__builtin_ia32_pcmpgtw",
+    "llvm.x86.mmx.pextr.w" => "__builtin_ia32_vec_ext_v4hi",
+    "llvm.x86.mmx.pinsr.w" => "__builtin_ia32_vec_set_v4hi",
+    "llvm.x86.mmx.pmadd.wd" => "__builtin_ia32_pmaddwd",
+    "llvm.x86.mmx.pmaxs.w" => "__builtin_ia32_pmaxsw",
+    "llvm.x86.mmx.pmaxu.b" => "__builtin_ia32_pmaxub",
+    "llvm.x86.mmx.pmins.w" => "__builtin_ia32_pminsw",
+    "llvm.x86.mmx.pminu.b" => "__builtin_ia32_pminub",
+    "llvm.x86.mmx.pmovmskb" => "__builtin_ia32_pmovmskb",
+    "llvm.x86.mmx.pmulh.w" => "__builtin_ia32_pmulhw",
+    "llvm.x86.mmx.pmulhu.w" => "__builtin_ia32_pmulhuw",
+    "llvm.x86.mmx.pmull.w" => "__builtin_ia32_pmullw",
+    "llvm.x86.mmx.pmulu.dq" => "__builtin_ia32_pmuludq",
+    "llvm.x86.mmx.por" => "__builtin_ia32_por",
+    "llvm.x86.mmx.psad.bw" => "__builtin_ia32_psadbw",
+    "llvm.x86.mmx.psll.d" => "__builtin_ia32_pslld",
+    "llvm.x86.mmx.psll.q" => "__builtin_ia32_psllq",
+    "llvm.x86.mmx.psll.w" => "__builtin_ia32_psllw",
+    "llvm.x86.mmx.pslli.d" => "__builtin_ia32_pslldi",
+    "llvm.x86.mmx.pslli.q" => "__builtin_ia32_psllqi",
+    "llvm.x86.mmx.pslli.w" => "__builtin_ia32_psllwi",
+    "llvm.x86.mmx.psra.d" => "__builtin_ia32_psrad",
+    "llvm.x86.mmx.psra.w" => "__builtin_ia32_psraw",
+    "llvm.x86.mmx.psrai.d" => "__builtin_ia32_psradi",
+    "llvm.x86.mmx.psrai.w" => "__builtin_ia32_psrawi",
+    "llvm.x86.mmx.psrl.d" => "__builtin_ia32_psrld",
+    "llvm.x86.mmx.psrl.q" => "__builtin_ia32_psrlq",
+    "llvm.x86.mmx.psrl.w" => "__builtin_ia32_psrlw",
+    "llvm.x86.mmx.psrli.d" => "__builtin_ia32_psrldi",
+    "llvm.x86.mmx.psrli.q" => "__builtin_ia32_psrlqi",
+    "llvm.x86.mmx.psrli.w" => "__builtin_ia32_psrlwi",
+    "llvm.x86.mmx.psub.b" => "__builtin_ia32_psubb",
+    "llvm.x86.mmx.psub.d" => "__builtin_ia32_psubd",
+    "llvm.x86.mmx.psub.q" => "__builtin_ia32_psubq",
+    "llvm.x86.mmx.psub.w" => "__builtin_ia32_psubw",
+    "llvm.x86.mmx.psubs.b" => "__builtin_ia32_psubsb",
+    "llvm.x86.mmx.psubs.w" => "__builtin_ia32_psubsw",
+    "llvm.x86.mmx.psubus.b" => "__builtin_ia32_psubusb",
+    "llvm.x86.mmx.psubus.w" => "__builtin_ia32_psubusw",
+    "llvm.x86.mmx.punpckhbw" => "__builtin_ia32_punpckhbw",
+    "llvm.x86.mmx.punpckhdq" => "__builtin_ia32_punpckhdq",
+    "llvm.x86.mmx.punpckhwd" => "__builtin_ia32_punpckhwd",
+    "llvm.x86.mmx.punpcklbw" => "__builtin_ia32_punpcklbw",
+    "llvm.x86.mmx.punpckldq" => "__builtin_ia32_punpckldq",
+    "llvm.x86.mmx.punpcklwd" => "__builtin_ia32_punpcklwd",
+    "llvm.x86.mmx.pxor" => "__builtin_ia32_pxor",
+    "llvm.x86.monitorx" => "__builtin_ia32_monitorx",
+    "llvm.x86.movdir64b" => "__builtin_ia32_movdir64b",
+    "llvm.x86.mwaitx" => "__builtin_ia32_mwaitx",
+    "llvm.x86.pclmulqdq" => "__builtin_ia32_pclmulqdq128",
+    "llvm.x86.pclmulqdq.256" => "__builtin_ia32_pclmulqdq256",
+    "llvm.x86.pclmulqdq.512" => "__builtin_ia32_pclmulqdq512",
+    "llvm.x86.ptwrite32" => "__builtin_ia32_ptwrite32",
+    "llvm.x86.ptwrite64" => "__builtin_ia32_ptwrite64",
+    "llvm.x86.rdfsbase.32" => "__builtin_ia32_rdfsbase32",
+    "llvm.x86.rdfsbase.64" => "__builtin_ia32_rdfsbase64",
+    "llvm.x86.rdgsbase.32" => "__builtin_ia32_rdgsbase32",
+    "llvm.x86.rdgsbase.64" => "__builtin_ia32_rdgsbase64",
+    "llvm.x86.rdpid" => "__builtin_ia32_rdpid",
+    "llvm.x86.rdpkru" => "__builtin_ia32_rdpkru",
+    "llvm.x86.rdpmc" => "__builtin_ia32_rdpmc",
+    "llvm.x86.rdsspd" => "__builtin_ia32_rdsspd",
+    "llvm.x86.rdsspq" => "__builtin_ia32_rdsspq",
+    "llvm.x86.rdtsc" => "__builtin_ia32_rdtsc",
+    "llvm.x86.rdtscp" => "__builtin_ia32_rdtscp",
+    "llvm.x86.rstorssp" => "__builtin_ia32_rstorssp",
+    "llvm.x86.saveprevssp" => "__builtin_ia32_saveprevssp",
+    "llvm.x86.senduipi" => "__builtin_ia32_senduipi",
+    "llvm.x86.serialize" => "__builtin_ia32_serialize",
+    "llvm.x86.setssbsy" => "__builtin_ia32_setssbsy",
+    "llvm.x86.sha1msg1" => "__builtin_ia32_sha1msg1",
+    "llvm.x86.sha1msg2" => "__builtin_ia32_sha1msg2",
+    "llvm.x86.sha1nexte" => "__builtin_ia32_sha1nexte",
+    "llvm.x86.sha1rnds4" => "__builtin_ia32_sha1rnds4",
+    "llvm.x86.sha256msg1" => "__builtin_ia32_sha256msg1",
+    "llvm.x86.sha256msg2" => "__builtin_ia32_sha256msg2",
+    "llvm.x86.sha256rnds2" => "__builtin_ia32_sha256rnds2",
+    "llvm.x86.slwpcb" => "__builtin_ia32_slwpcb",
+    "llvm.x86.sse.add.ss" => "__builtin_ia32_addss",
+    "llvm.x86.sse.cmp.ps" => "__builtin_ia32_cmpps",
+    "llvm.x86.sse.cmp.ss" => "__builtin_ia32_cmpss",
+    "llvm.x86.sse.comieq.ss" => "__builtin_ia32_comieq",
+    "llvm.x86.sse.comige.ss" => "__builtin_ia32_comige",
+    "llvm.x86.sse.comigt.ss" => "__builtin_ia32_comigt",
+    "llvm.x86.sse.comile.ss" => "__builtin_ia32_comile",
+    "llvm.x86.sse.comilt.ss" => "__builtin_ia32_comilt",
+    "llvm.x86.sse.comineq.ss" => "__builtin_ia32_comineq",
+    "llvm.x86.sse.cvtpd2pi" => "__builtin_ia32_cvtpd2pi",
+    "llvm.x86.sse.cvtpi2pd" => "__builtin_ia32_cvtpi2pd",
+    "llvm.x86.sse.cvtpi2ps" => "__builtin_ia32_cvtpi2ps",
+    "llvm.x86.sse.cvtps2pi" => "__builtin_ia32_cvtps2pi",
+    "llvm.x86.sse.cvtsi2ss" => "__builtin_ia32_cvtsi2ss",
+    "llvm.x86.sse.cvtsi642ss" => "__builtin_ia32_cvtsi642ss",
+    "llvm.x86.sse.cvtss2si" => "__builtin_ia32_cvtss2si",
+    "llvm.x86.sse.cvtss2si64" => "__builtin_ia32_cvtss2si64",
+    "llvm.x86.sse.cvttpd2pi" => "__builtin_ia32_cvttpd2pi",
+    "llvm.x86.sse.cvttps2pi" => "__builtin_ia32_cvttps2pi",
+    "llvm.x86.sse.cvttss2si" => "__builtin_ia32_cvttss2si",
+    "llvm.x86.sse.cvttss2si64" => "__builtin_ia32_cvttss2si64",
+    "llvm.x86.sse.div.ss" => "__builtin_ia32_divss",
+    "llvm.x86.sse.max.ps" => "__builtin_ia32_maxps",
+    "llvm.x86.sse.max.ss" => "__builtin_ia32_maxss",
+    "llvm.x86.sse.min.ps" => "__builtin_ia32_minps",
+    "llvm.x86.sse.min.ss" => "__builtin_ia32_minss",
+    "llvm.x86.sse.movmsk.ps" => "__builtin_ia32_movmskps",
+    "llvm.x86.sse.mul.ss" => "__builtin_ia32_mulss",
+    "llvm.x86.sse.pshuf.w" => "__builtin_ia32_pshufw",
+    "llvm.x86.sse.rcp.ps" => "__builtin_ia32_rcpps",
+    "llvm.x86.sse.rcp.ss" => "__builtin_ia32_rcpss",
+    "llvm.x86.sse.rsqrt.ps" => "__builtin_ia32_rsqrtps",
+    "llvm.x86.sse.rsqrt.ss" => "__builtin_ia32_rsqrtss",
+    "llvm.x86.sse.sfence" => "__builtin_ia32_sfence",
+    "llvm.x86.sse.sqrt.ps" => "__builtin_ia32_sqrtps",
+    "llvm.x86.sse.sqrt.ss" => "__builtin_ia32_sqrtss",
+    "llvm.x86.sse.storeu.ps" => "__builtin_ia32_storeups",
+    "llvm.x86.sse.sub.ss" => "__builtin_ia32_subss",
+    "llvm.x86.sse.ucomieq.ss" => "__builtin_ia32_ucomieq",
+    "llvm.x86.sse.ucomige.ss" => "__builtin_ia32_ucomige",
+    "llvm.x86.sse.ucomigt.ss" => "__builtin_ia32_ucomigt",
+    "llvm.x86.sse.ucomile.ss" => "__builtin_ia32_ucomile",
+    "llvm.x86.sse.ucomilt.ss" => "__builtin_ia32_ucomilt",
+    "llvm.x86.sse.ucomineq.ss" => "__builtin_ia32_ucomineq",
+    "llvm.x86.sse2.add.sd" => "__builtin_ia32_addsd",
+    "llvm.x86.sse2.clflush" => "__builtin_ia32_clflush",
+    "llvm.x86.sse2.cmp.pd" => "__builtin_ia32_cmppd",
+    "llvm.x86.sse2.cmp.sd" => "__builtin_ia32_cmpsd",
+    "llvm.x86.sse2.comieq.sd" => "__builtin_ia32_comisdeq",
+    "llvm.x86.sse2.comige.sd" => "__builtin_ia32_comisdge",
+    "llvm.x86.sse2.comigt.sd" => "__builtin_ia32_comisdgt",
+    "llvm.x86.sse2.comile.sd" => "__builtin_ia32_comisdle",
+    "llvm.x86.sse2.comilt.sd" => "__builtin_ia32_comisdlt",
+    "llvm.x86.sse2.comineq.sd" => "__builtin_ia32_comisdneq",
+    "llvm.x86.sse2.cvtdq2pd" => "__builtin_ia32_cvtdq2pd",
+    "llvm.x86.sse2.cvtdq2ps" => "__builtin_ia32_cvtdq2ps",
+    "llvm.x86.sse2.cvtpd2dq" => "__builtin_ia32_cvtpd2dq",
+    "llvm.x86.sse2.cvtpd2ps" => "__builtin_ia32_cvtpd2ps",
+    "llvm.x86.sse2.cvtps2dq" => "__builtin_ia32_cvtps2dq",
+    "llvm.x86.sse2.cvtps2pd" => "__builtin_ia32_cvtps2pd",
+    "llvm.x86.sse2.cvtsd2si" => "__builtin_ia32_cvtsd2si",
+    "llvm.x86.sse2.cvtsd2si64" => "__builtin_ia32_cvtsd2si64",
+    "llvm.x86.sse2.cvtsd2ss" => "__builtin_ia32_cvtsd2ss",
+    "llvm.x86.sse2.cvtsi2sd" => "__builtin_ia32_cvtsi2sd",
+    "llvm.x86.sse2.cvtsi642sd" => "__builtin_ia32_cvtsi642sd",
+    "llvm.x86.sse2.cvtss2sd" => "__builtin_ia32_cvtss2sd",
+    "llvm.x86.sse2.cvttpd2dq" => "__builtin_ia32_cvttpd2dq",
+    "llvm.x86.sse2.cvttps2dq" => "__builtin_ia32_cvttps2dq",
+    "llvm.x86.sse2.cvttsd2si" => "__builtin_ia32_cvttsd2si",
+    "llvm.x86.sse2.cvttsd2si64" => "__builtin_ia32_cvttsd2si64",
+    "llvm.x86.sse2.div.sd" => "__builtin_ia32_divsd",
+    "llvm.x86.sse2.lfence" => "__builtin_ia32_lfence",
+    "llvm.x86.sse2.maskmov.dqu" => "__builtin_ia32_maskmovdqu",
+    "llvm.x86.sse2.max.pd" => "__builtin_ia32_maxpd",
+    "llvm.x86.sse2.max.sd" => "__builtin_ia32_maxsd",
+    "llvm.x86.sse2.mfence" => "__builtin_ia32_mfence",
+    "llvm.x86.sse2.min.pd" => "__builtin_ia32_minpd",
+    "llvm.x86.sse2.min.sd" => "__builtin_ia32_minsd",
+    "llvm.x86.sse2.movmsk.pd" => "__builtin_ia32_movmskpd",
+    "llvm.x86.sse2.mul.sd" => "__builtin_ia32_mulsd",
+    "llvm.x86.sse2.packssdw.128" => "__builtin_ia32_packssdw128",
+    "llvm.x86.sse2.packsswb.128" => "__builtin_ia32_packsswb128",
+    "llvm.x86.sse2.packuswb.128" => "__builtin_ia32_packuswb128",
+    "llvm.x86.sse2.padds.b" => "__builtin_ia32_paddsb128",
+    "llvm.x86.sse2.padds.w" => "__builtin_ia32_paddsw128",
+    "llvm.x86.sse2.paddus.b" => "__builtin_ia32_paddusb128",
+    "llvm.x86.sse2.paddus.w" => "__builtin_ia32_paddusw128",
+    "llvm.x86.sse2.pause" => "__builtin_ia32_pause",
+    "llvm.x86.sse2.pavg.b" => "__builtin_ia32_pavgb128",
+    "llvm.x86.sse2.pavg.w" => "__builtin_ia32_pavgw128",
+    "llvm.x86.sse2.pmadd.wd" => "__builtin_ia32_pmaddwd128",
+    "llvm.x86.sse2.pmaxs.w" => "__builtin_ia32_pmaxsw128",
+    "llvm.x86.sse2.pmaxu.b" => "__builtin_ia32_pmaxub128",
+    "llvm.x86.sse2.pmins.w" => "__builtin_ia32_pminsw128",
+    "llvm.x86.sse2.pminu.b" => "__builtin_ia32_pminub128",
+    "llvm.x86.sse2.pmovmskb.128" => "__builtin_ia32_pmovmskb128",
+    "llvm.x86.sse2.pmulh.w" => "__builtin_ia32_pmulhw128",
+    "llvm.x86.sse2.pmulhu.w" => "__builtin_ia32_pmulhuw128",
+    "llvm.x86.sse2.pmulu.dq" => "__builtin_ia32_pmuludq128",
+    "llvm.x86.sse2.psad.bw" => "__builtin_ia32_psadbw128",
+    "llvm.x86.sse2.pshuf.d" => "__builtin_ia32_pshufd",
+    "llvm.x86.sse2.pshufh.w" => "__builtin_ia32_pshufhw",
+    "llvm.x86.sse2.pshufl.w" => "__builtin_ia32_pshuflw",
+    "llvm.x86.sse2.psll.d" => "__builtin_ia32_pslld128",
+    "llvm.x86.sse2.psll.dq" => "__builtin_ia32_pslldqi128",
+    "llvm.x86.sse2.psll.dq.bs" => "__builtin_ia32_pslldqi128_byteshift",
+    "llvm.x86.sse2.psll.q" => "__builtin_ia32_psllq128",
+    "llvm.x86.sse2.psll.w" => "__builtin_ia32_psllw128",
+    "llvm.x86.sse2.pslli.d" => "__builtin_ia32_pslldi128",
+    "llvm.x86.sse2.pslli.q" => "__builtin_ia32_psllqi128",
+    "llvm.x86.sse2.pslli.w" => "__builtin_ia32_psllwi128",
+    "llvm.x86.sse2.psra.d" => "__builtin_ia32_psrad128",
+    "llvm.x86.sse2.psra.w" => "__builtin_ia32_psraw128",
+    "llvm.x86.sse2.psrai.d" => "__builtin_ia32_psradi128",
+    "llvm.x86.sse2.psrai.w" => "__builtin_ia32_psrawi128",
+    "llvm.x86.sse2.psrl.d" => "__builtin_ia32_psrld128",
+    "llvm.x86.sse2.psrl.dq" => "__builtin_ia32_psrldqi128",
+    "llvm.x86.sse2.psrl.dq.bs" => "__builtin_ia32_psrldqi128_byteshift",
+    "llvm.x86.sse2.psrl.q" => "__builtin_ia32_psrlq128",
+    "llvm.x86.sse2.psrl.w" => "__builtin_ia32_psrlw128",
+    "llvm.x86.sse2.psrli.d" => "__builtin_ia32_psrldi128",
+    "llvm.x86.sse2.psrli.q" => "__builtin_ia32_psrlqi128",
+    "llvm.x86.sse2.psrli.w" => "__builtin_ia32_psrlwi128",
+    "llvm.x86.sse2.psubs.b" => "__builtin_ia32_psubsb128",
+    "llvm.x86.sse2.psubs.w" => "__builtin_ia32_psubsw128",
+    "llvm.x86.sse2.psubus.b" => "__builtin_ia32_psubusb128",
+    "llvm.x86.sse2.psubus.w" => "__builtin_ia32_psubusw128",
+    "llvm.x86.sse2.sqrt.pd" => "__builtin_ia32_sqrtpd",
+    "llvm.x86.sse2.sqrt.sd" => "__builtin_ia32_sqrtsd",
+    "llvm.x86.sse2.storel.dq" => "__builtin_ia32_storelv4si",
+    "llvm.x86.sse2.storeu.dq" => "__builtin_ia32_storedqu",
+    "llvm.x86.sse2.storeu.pd" => "__builtin_ia32_storeupd",
+    "llvm.x86.sse2.sub.sd" => "__builtin_ia32_subsd",
+    "llvm.x86.sse2.ucomieq.sd" => "__builtin_ia32_ucomisdeq",
+    "llvm.x86.sse2.ucomige.sd" => "__builtin_ia32_ucomisdge",
+    "llvm.x86.sse2.ucomigt.sd" => "__builtin_ia32_ucomisdgt",
+    "llvm.x86.sse2.ucomile.sd" => "__builtin_ia32_ucomisdle",
+    "llvm.x86.sse2.ucomilt.sd" => "__builtin_ia32_ucomisdlt",
+    "llvm.x86.sse2.ucomineq.sd" => "__builtin_ia32_ucomisdneq",
+    "llvm.x86.sse3.addsub.pd" => "__builtin_ia32_addsubpd",
+    "llvm.x86.sse3.addsub.ps" => "__builtin_ia32_addsubps",
+    "llvm.x86.sse3.hadd.pd" => "__builtin_ia32_haddpd",
+    "llvm.x86.sse3.hadd.ps" => "__builtin_ia32_haddps",
+    "llvm.x86.sse3.hsub.pd" => "__builtin_ia32_hsubpd",
+    "llvm.x86.sse3.hsub.ps" => "__builtin_ia32_hsubps",
+    "llvm.x86.sse3.ldu.dq" => "__builtin_ia32_lddqu",
+    "llvm.x86.sse3.monitor" => "__builtin_ia32_monitor",
+    "llvm.x86.sse3.mwait" => "__builtin_ia32_mwait",
+    "llvm.x86.sse41.blendpd" => "__builtin_ia32_blendpd",
+    "llvm.x86.sse41.blendps" => "__builtin_ia32_blendps",
+    "llvm.x86.sse41.blendvpd" => "__builtin_ia32_blendvpd",
+    "llvm.x86.sse41.blendvps" => "__builtin_ia32_blendvps",
+    "llvm.x86.sse41.dppd" => "__builtin_ia32_dppd",
+    "llvm.x86.sse41.dpps" => "__builtin_ia32_dpps",
+    "llvm.x86.sse41.extractps" => "__builtin_ia32_extractps128",
+    "llvm.x86.sse41.insertps" => "__builtin_ia32_insertps128",
+    "llvm.x86.sse41.movntdqa" => "__builtin_ia32_movntdqa",
+    "llvm.x86.sse41.mpsadbw" => "__builtin_ia32_mpsadbw128",
+    "llvm.x86.sse41.packusdw" => "__builtin_ia32_packusdw128",
+    "llvm.x86.sse41.pblendvb" => "__builtin_ia32_pblendvb128",
+    "llvm.x86.sse41.pblendw" => "__builtin_ia32_pblendw128",
+    "llvm.x86.sse41.phminposuw" => "__builtin_ia32_phminposuw128",
+    "llvm.x86.sse41.pmaxsb" => "__builtin_ia32_pmaxsb128",
+    "llvm.x86.sse41.pmaxsd" => "__builtin_ia32_pmaxsd128",
+    "llvm.x86.sse41.pmaxud" => "__builtin_ia32_pmaxud128",
+    "llvm.x86.sse41.pmaxuw" => "__builtin_ia32_pmaxuw128",
+    "llvm.x86.sse41.pminsb" => "__builtin_ia32_pminsb128",
+    "llvm.x86.sse41.pminsd" => "__builtin_ia32_pminsd128",
+    "llvm.x86.sse41.pminud" => "__builtin_ia32_pminud128",
+    "llvm.x86.sse41.pminuw" => "__builtin_ia32_pminuw128",
+    "llvm.x86.sse41.pmovsxbd" => "__builtin_ia32_pmovsxbd128",
+    "llvm.x86.sse41.pmovsxbq" => "__builtin_ia32_pmovsxbq128",
+    "llvm.x86.sse41.pmovsxbw" => "__builtin_ia32_pmovsxbw128",
+    "llvm.x86.sse41.pmovsxdq" => "__builtin_ia32_pmovsxdq128",
+    "llvm.x86.sse41.pmovsxwd" => "__builtin_ia32_pmovsxwd128",
+    "llvm.x86.sse41.pmovsxwq" => "__builtin_ia32_pmovsxwq128",
+    "llvm.x86.sse41.pmovzxbd" => "__builtin_ia32_pmovzxbd128",
+    "llvm.x86.sse41.pmovzxbq" => "__builtin_ia32_pmovzxbq128",
+    "llvm.x86.sse41.pmovzxbw" => "__builtin_ia32_pmovzxbw128",
+    "llvm.x86.sse41.pmovzxdq" => "__builtin_ia32_pmovzxdq128",
+    "llvm.x86.sse41.pmovzxwd" => "__builtin_ia32_pmovzxwd128",
+    "llvm.x86.sse41.pmovzxwq" => "__builtin_ia32_pmovzxwq128",
+    "llvm.x86.sse41.pmuldq" => "__builtin_ia32_pmuldq128",
+    "llvm.x86.sse41.ptestc" => "__builtin_ia32_ptestc128",
+    "llvm.x86.sse41.ptestnzc" => "__builtin_ia32_ptestnzc128",
+    "llvm.x86.sse41.ptestz" => "__builtin_ia32_ptestz128",
+    "llvm.x86.sse41.round.pd" => "__builtin_ia32_roundpd",
+    "llvm.x86.sse41.round.ps" => "__builtin_ia32_roundps",
+    "llvm.x86.sse41.round.sd" => "__builtin_ia32_roundsd",
+    "llvm.x86.sse41.round.ss" => "__builtin_ia32_roundss",
+    "llvm.x86.sse42.crc32.32.16" => "__builtin_ia32_crc32hi",
+    "llvm.x86.sse42.crc32.32.32" => "__builtin_ia32_crc32si",
+    "llvm.x86.sse42.crc32.32.8" => "__builtin_ia32_crc32qi",
+    "llvm.x86.sse42.crc32.64.64" => "__builtin_ia32_crc32di",
+    "llvm.x86.sse42.pcmpestri128" => "__builtin_ia32_pcmpestri128",
+    "llvm.x86.sse42.pcmpestria128" => "__builtin_ia32_pcmpestria128",
+    "llvm.x86.sse42.pcmpestric128" => "__builtin_ia32_pcmpestric128",
+    "llvm.x86.sse42.pcmpestrio128" => "__builtin_ia32_pcmpestrio128",
+    "llvm.x86.sse42.pcmpestris128" => "__builtin_ia32_pcmpestris128",
+    "llvm.x86.sse42.pcmpestriz128" => "__builtin_ia32_pcmpestriz128",
+    "llvm.x86.sse42.pcmpestrm128" => "__builtin_ia32_pcmpestrm128",
+    "llvm.x86.sse42.pcmpistri128" => "__builtin_ia32_pcmpistri128",
+    "llvm.x86.sse42.pcmpistria128" => "__builtin_ia32_pcmpistria128",
+    "llvm.x86.sse42.pcmpistric128" => "__builtin_ia32_pcmpistric128",
+    "llvm.x86.sse42.pcmpistrio128" => "__builtin_ia32_pcmpistrio128",
+    "llvm.x86.sse42.pcmpistris128" => "__builtin_ia32_pcmpistris128",
+    "llvm.x86.sse42.pcmpistriz128" => "__builtin_ia32_pcmpistriz128",
+    "llvm.x86.sse42.pcmpistrm128" => "__builtin_ia32_pcmpistrm128",
+    "llvm.x86.sse4a.extrq" => "__builtin_ia32_extrq",
+    "llvm.x86.sse4a.extrqi" => "__builtin_ia32_extrqi",
+    "llvm.x86.sse4a.insertq" => "__builtin_ia32_insertq",
+    "llvm.x86.sse4a.insertqi" => "__builtin_ia32_insertqi",
+    "llvm.x86.sse4a.movnt.sd" => "__builtin_ia32_movntsd",
+    "llvm.x86.sse4a.movnt.ss" => "__builtin_ia32_movntss",
+    "llvm.x86.ssse3.pabs.b" => "__builtin_ia32_pabsb",
+    "llvm.x86.ssse3.pabs.b.128" => "__builtin_ia32_pabsb128",
+    "llvm.x86.ssse3.pabs.d" => "__builtin_ia32_pabsd",
+    "llvm.x86.ssse3.pabs.d.128" => "__builtin_ia32_pabsd128",
+    "llvm.x86.ssse3.pabs.w" => "__builtin_ia32_pabsw",
+    "llvm.x86.ssse3.pabs.w.128" => "__builtin_ia32_pabsw128",
+    "llvm.x86.ssse3.phadd.d" => "__builtin_ia32_phaddd",
+    "llvm.x86.ssse3.phadd.d.128" => "__builtin_ia32_phaddd128",
+    "llvm.x86.ssse3.phadd.sw" => "__builtin_ia32_phaddsw",
+    "llvm.x86.ssse3.phadd.sw.128" => "__builtin_ia32_phaddsw128",
+    "llvm.x86.ssse3.phadd.w" => "__builtin_ia32_phaddw",
+    "llvm.x86.ssse3.phadd.w.128" => "__builtin_ia32_phaddw128",
+    "llvm.x86.ssse3.phsub.d" => "__builtin_ia32_phsubd",
+    "llvm.x86.ssse3.phsub.d.128" => "__builtin_ia32_phsubd128",
+    "llvm.x86.ssse3.phsub.sw" => "__builtin_ia32_phsubsw",
+    "llvm.x86.ssse3.phsub.sw.128" => "__builtin_ia32_phsubsw128",
+    "llvm.x86.ssse3.phsub.w" => "__builtin_ia32_phsubw",
+    "llvm.x86.ssse3.phsub.w.128" => "__builtin_ia32_phsubw128",
+    "llvm.x86.ssse3.pmadd.ub.sw" => "__builtin_ia32_pmaddubsw",
+    "llvm.x86.ssse3.pmadd.ub.sw.128" => "__builtin_ia32_pmaddubsw128",
+    "llvm.x86.ssse3.pmul.hr.sw" => "__builtin_ia32_pmulhrsw",
+    "llvm.x86.ssse3.pmul.hr.sw.128" => "__builtin_ia32_pmulhrsw128",
+    "llvm.x86.ssse3.pshuf.b" => "__builtin_ia32_pshufb",
+    "llvm.x86.ssse3.pshuf.b.128" => "__builtin_ia32_pshufb128",
+    "llvm.x86.ssse3.psign.b" => "__builtin_ia32_psignb",
+    "llvm.x86.ssse3.psign.b.128" => "__builtin_ia32_psignb128",
+    "llvm.x86.ssse3.psign.d" => "__builtin_ia32_psignd",
+    "llvm.x86.ssse3.psign.d.128" => "__builtin_ia32_psignd128",
+    "llvm.x86.ssse3.psign.w" => "__builtin_ia32_psignw",
+    "llvm.x86.ssse3.psign.w.128" => "__builtin_ia32_psignw128",
+    "llvm.x86.sttilecfg" => "__builtin_ia32_tile_storeconfig",
+    "llvm.x86.stui" => "__builtin_ia32_stui",
+    "llvm.x86.subborrow.u32" => "__builtin_ia32_subborrow_u32",
+    "llvm.x86.subborrow.u64" => "__builtin_ia32_subborrow_u64",
+    "llvm.x86.tbm.bextri.u32" => "__builtin_ia32_bextri_u32",
+    "llvm.x86.tbm.bextri.u64" => "__builtin_ia32_bextri_u64",
+    "llvm.x86.tdpbf16ps" => "__builtin_ia32_tdpbf16ps",
+    "llvm.x86.tdpbf16ps.internal" => "__builtin_ia32_tdpbf16ps_internal",
+    "llvm.x86.tdpbssd" => "__builtin_ia32_tdpbssd",
+    "llvm.x86.tdpbssd.internal" => "__builtin_ia32_tdpbssd_internal",
+    "llvm.x86.tdpbsud" => "__builtin_ia32_tdpbsud",
+    "llvm.x86.tdpbsud.internal" => "__builtin_ia32_tdpbsud_internal",
+    "llvm.x86.tdpbusd" => "__builtin_ia32_tdpbusd",
+    "llvm.x86.tdpbusd.internal" => "__builtin_ia32_tdpbusd_internal",
+    "llvm.x86.tdpbuud" => "__builtin_ia32_tdpbuud",
+    "llvm.x86.tdpbuud.internal" => "__builtin_ia32_tdpbuud_internal",
+    "llvm.x86.testui" => "__builtin_ia32_testui",
+    "llvm.x86.tileloadd64" => "__builtin_ia32_tileloadd64",
+    "llvm.x86.tileloadd64.internal" => "__builtin_ia32_tileloadd64_internal",
+    "llvm.x86.tileloaddt164" => "__builtin_ia32_tileloaddt164",
+    "llvm.x86.tileloaddt164.internal" => "__builtin_ia32_tileloaddt164_internal",
+    "llvm.x86.tilerelease" => "__builtin_ia32_tilerelease",
+    "llvm.x86.tilestored64" => "__builtin_ia32_tilestored64",
+    "llvm.x86.tilestored64.internal" => "__builtin_ia32_tilestored64_internal",
+    "llvm.x86.tilezero" => "__builtin_ia32_tilezero",
+    "llvm.x86.tilezero.internal" => "__builtin_ia32_tilezero_internal",
+    "llvm.x86.tpause" => "__builtin_ia32_tpause",
+    "llvm.x86.umonitor" => "__builtin_ia32_umonitor",
+    "llvm.x86.umwait" => "__builtin_ia32_umwait",
+    "llvm.x86.vcvtph2ps.128" => "__builtin_ia32_vcvtph2ps",
+    "llvm.x86.vcvtph2ps.256" => "__builtin_ia32_vcvtph2ps256",
+    "llvm.x86.vcvtps2ph.128" => "__builtin_ia32_vcvtps2ph",
+    "llvm.x86.vcvtps2ph.256" => "__builtin_ia32_vcvtps2ph256",
+    "llvm.x86.vgf2p8affineinvqb.128" => "__builtin_ia32_vgf2p8affineinvqb_v16qi",
+    "llvm.x86.vgf2p8affineinvqb.256" => "__builtin_ia32_vgf2p8affineinvqb_v32qi",
+    "llvm.x86.vgf2p8affineinvqb.512" => "__builtin_ia32_vgf2p8affineinvqb_v64qi",
+    "llvm.x86.vgf2p8affineqb.128" => "__builtin_ia32_vgf2p8affineqb_v16qi",
+    "llvm.x86.vgf2p8affineqb.256" => "__builtin_ia32_vgf2p8affineqb_v32qi",
+    "llvm.x86.vgf2p8affineqb.512" => "__builtin_ia32_vgf2p8affineqb_v64qi",
+    "llvm.x86.vgf2p8mulb.128" => "__builtin_ia32_vgf2p8mulb_v16qi",
+    "llvm.x86.vgf2p8mulb.256" => "__builtin_ia32_vgf2p8mulb_v32qi",
+    "llvm.x86.vgf2p8mulb.512" => "__builtin_ia32_vgf2p8mulb_v64qi",
+    "llvm.x86.wbinvd" => "__builtin_ia32_wbinvd",
+    "llvm.x86.wbnoinvd" => "__builtin_ia32_wbnoinvd",
+    "llvm.x86.wrfsbase.32" => "__builtin_ia32_wrfsbase32",
+    "llvm.x86.wrfsbase.64" => "__builtin_ia32_wrfsbase64",
+    "llvm.x86.wrgsbase.32" => "__builtin_ia32_wrgsbase32",
+    "llvm.x86.wrgsbase.64" => "__builtin_ia32_wrgsbase64",
+    "llvm.x86.wrpkru" => "__builtin_ia32_wrpkru",
+    "llvm.x86.wrssd" => "__builtin_ia32_wrssd",
+    "llvm.x86.wrssq" => "__builtin_ia32_wrssq",
+    "llvm.x86.wrussd" => "__builtin_ia32_wrussd",
+    "llvm.x86.wrussq" => "__builtin_ia32_wrussq",
+    "llvm.x86.xabort" => "__builtin_ia32_xabort",
+    "llvm.x86.xbegin" => "__builtin_ia32_xbegin",
+    "llvm.x86.xend" => "__builtin_ia32_xend",
+    "llvm.x86.xop.vfrcz.pd" => "__builtin_ia32_vfrczpd",
+    "llvm.x86.xop.vfrcz.pd.256" => "__builtin_ia32_vfrczpd256",
+    "llvm.x86.xop.vfrcz.ps" => "__builtin_ia32_vfrczps",
+    "llvm.x86.xop.vfrcz.ps.256" => "__builtin_ia32_vfrczps256",
+    "llvm.x86.xop.vfrcz.sd" => "__builtin_ia32_vfrczsd",
+    "llvm.x86.xop.vfrcz.ss" => "__builtin_ia32_vfrczss",
+    "llvm.x86.xop.vpcmov" => "__builtin_ia32_vpcmov",
+    "llvm.x86.xop.vpcmov.256" => "__builtin_ia32_vpcmov_256",
+    "llvm.x86.xop.vpcomb" => "__builtin_ia32_vpcomb",
+    "llvm.x86.xop.vpcomd" => "__builtin_ia32_vpcomd",
+    "llvm.x86.xop.vpcomq" => "__builtin_ia32_vpcomq",
+    "llvm.x86.xop.vpcomub" => "__builtin_ia32_vpcomub",
+    "llvm.x86.xop.vpcomud" => "__builtin_ia32_vpcomud",
+    "llvm.x86.xop.vpcomuq" => "__builtin_ia32_vpcomuq",
+    "llvm.x86.xop.vpcomuw" => "__builtin_ia32_vpcomuw",
+    "llvm.x86.xop.vpcomw" => "__builtin_ia32_vpcomw",
+    "llvm.x86.xop.vpermil2pd" => "__builtin_ia32_vpermil2pd",
+    "llvm.x86.xop.vpermil2pd.256" => "__builtin_ia32_vpermil2pd256",
+    "llvm.x86.xop.vpermil2ps" => "__builtin_ia32_vpermil2ps",
+    "llvm.x86.xop.vpermil2ps.256" => "__builtin_ia32_vpermil2ps256",
+    "llvm.x86.xop.vphaddbd" => "__builtin_ia32_vphaddbd",
+    "llvm.x86.xop.vphaddbq" => "__builtin_ia32_vphaddbq",
+    "llvm.x86.xop.vphaddbw" => "__builtin_ia32_vphaddbw",
+    "llvm.x86.xop.vphadddq" => "__builtin_ia32_vphadddq",
+    "llvm.x86.xop.vphaddubd" => "__builtin_ia32_vphaddubd",
+    "llvm.x86.xop.vphaddubq" => "__builtin_ia32_vphaddubq",
+    "llvm.x86.xop.vphaddubw" => "__builtin_ia32_vphaddubw",
+    "llvm.x86.xop.vphaddudq" => "__builtin_ia32_vphaddudq",
+    "llvm.x86.xop.vphadduwd" => "__builtin_ia32_vphadduwd",
+    "llvm.x86.xop.vphadduwq" => "__builtin_ia32_vphadduwq",
+    "llvm.x86.xop.vphaddwd" => "__builtin_ia32_vphaddwd",
+    "llvm.x86.xop.vphaddwq" => "__builtin_ia32_vphaddwq",
+    "llvm.x86.xop.vphsubbw" => "__builtin_ia32_vphsubbw",
+    "llvm.x86.xop.vphsubdq" => "__builtin_ia32_vphsubdq",
+    "llvm.x86.xop.vphsubwd" => "__builtin_ia32_vphsubwd",
+    "llvm.x86.xop.vpmacsdd" => "__builtin_ia32_vpmacsdd",
+    "llvm.x86.xop.vpmacsdqh" => "__builtin_ia32_vpmacsdqh",
+    "llvm.x86.xop.vpmacsdql" => "__builtin_ia32_vpmacsdql",
+    "llvm.x86.xop.vpmacssdd" => "__builtin_ia32_vpmacssdd",
+    "llvm.x86.xop.vpmacssdqh" => "__builtin_ia32_vpmacssdqh",
+    "llvm.x86.xop.vpmacssdql" => "__builtin_ia32_vpmacssdql",
+    "llvm.x86.xop.vpmacsswd" => "__builtin_ia32_vpmacsswd",
+    "llvm.x86.xop.vpmacssww" => "__builtin_ia32_vpmacssww",
+    "llvm.x86.xop.vpmacswd" => "__builtin_ia32_vpmacswd",
+    "llvm.x86.xop.vpmacsww" => "__builtin_ia32_vpmacsww",
+    "llvm.x86.xop.vpmadcsswd" => "__builtin_ia32_vpmadcsswd",
+    "llvm.x86.xop.vpmadcswd" => "__builtin_ia32_vpmadcswd",
+    "llvm.x86.xop.vpperm" => "__builtin_ia32_vpperm",
+    "llvm.x86.xop.vprotb" => "__builtin_ia32_vprotb",
+    "llvm.x86.xop.vprotbi" => "__builtin_ia32_vprotbi",
+    "llvm.x86.xop.vprotd" => "__builtin_ia32_vprotd",
+    "llvm.x86.xop.vprotdi" => "__builtin_ia32_vprotdi",
+    "llvm.x86.xop.vprotq" => "__builtin_ia32_vprotq",
+    "llvm.x86.xop.vprotqi" => "__builtin_ia32_vprotqi",
+    "llvm.x86.xop.vprotw" => "__builtin_ia32_vprotw",
+    "llvm.x86.xop.vprotwi" => "__builtin_ia32_vprotwi",
+    "llvm.x86.xop.vpshab" => "__builtin_ia32_vpshab",
+    "llvm.x86.xop.vpshad" => "__builtin_ia32_vpshad",
+    "llvm.x86.xop.vpshaq" => "__builtin_ia32_vpshaq",
+    "llvm.x86.xop.vpshaw" => "__builtin_ia32_vpshaw",
+    "llvm.x86.xop.vpshlb" => "__builtin_ia32_vpshlb",
+    "llvm.x86.xop.vpshld" => "__builtin_ia32_vpshld",
+    "llvm.x86.xop.vpshlq" => "__builtin_ia32_vpshlq",
+    "llvm.x86.xop.vpshlw" => "__builtin_ia32_vpshlw",
+    "llvm.x86.xresldtrk" => "__builtin_ia32_xresldtrk",
+    "llvm.x86.xsusldtrk" => "__builtin_ia32_xsusldtrk",
+    "llvm.x86.xtest" => "__builtin_ia32_xtest",
+    // xcore
+    "llvm.xcore.bitrev" => "__builtin_bitrev",
+    "llvm.xcore.getid" => "__builtin_getid",
+    "llvm.xcore.getps" => "__builtin_getps",
+    "llvm.xcore.setps" => "__builtin_setps",
+    _ => unimplemented!("***** unsupported LLVM intrinsic {}", name),
+}
diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/llvm.rs b/compiler/rustc_codegen_gcc/src/intrinsic/llvm.rs
index b074feb..1b089f0 100644
--- a/compiler/rustc_codegen_gcc/src/intrinsic/llvm.rs
+++ b/compiler/rustc_codegen_gcc/src/intrinsic/llvm.rs
@@ -1,22 +1,250 @@
-use gccjit::Function;
+use std::borrow::Cow;
 
-use crate::context::CodegenCx;
+use gccjit::{Function, FunctionPtrType, RValue, ToRValue};
 
-pub fn intrinsic<'gcc, 'tcx>(name: &str, cx: &CodegenCx<'gcc, 'tcx>) -> Function<'gcc> {
-    let _gcc_name =
-        match name {
-            "llvm.x86.xgetbv" => {
-                let gcc_name = "__builtin_trap";
-                let func = cx.context.get_builtin_function(gcc_name);
-                cx.functions.borrow_mut().insert(gcc_name.to_string(), func);
-                return func;
+use crate::{context::CodegenCx, builder::Builder};
+
+pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>(builder: &Builder<'a, 'gcc, 'tcx>, gcc_func: FunctionPtrType<'gcc>, mut args: Cow<'b, [RValue<'gcc>]>, func_name: &str) -> Cow<'b, [RValue<'gcc>]> {
+    // Some LLVM intrinsics do not map 1-to-1 to GCC intrinsics, so we add the missing
+    // arguments here.
+    if gcc_func.get_param_count() != args.len() {
+        match &*func_name {
+            "__builtin_ia32_pmuldq512_mask" | "__builtin_ia32_pmuludq512_mask"
+                // FIXME(antoyo): the following intrinsics has 4 (or 5) arguments according to the doc, but is defined with 2 (or 3) arguments in library/stdarch/crates/core_arch/src/x86/avx512f.rs.
+                | "__builtin_ia32_pmaxsd512_mask" | "__builtin_ia32_pmaxsq512_mask" | "__builtin_ia32_pmaxsq256_mask"
+                | "__builtin_ia32_pmaxsq128_mask" | "__builtin_ia32_maxps512_mask" | "__builtin_ia32_maxpd512_mask"
+                | "__builtin_ia32_pmaxud512_mask" | "__builtin_ia32_pmaxuq512_mask" | "__builtin_ia32_pmaxuq256_mask"
+                | "__builtin_ia32_pmaxuq128_mask"
+                | "__builtin_ia32_pminsd512_mask" | "__builtin_ia32_pminsq512_mask" | "__builtin_ia32_pminsq256_mask"
+                | "__builtin_ia32_pminsq128_mask" | "__builtin_ia32_minps512_mask" | "__builtin_ia32_minpd512_mask"
+                | "__builtin_ia32_pminud512_mask" | "__builtin_ia32_pminuq512_mask" | "__builtin_ia32_pminuq256_mask"
+                | "__builtin_ia32_pminuq128_mask" | "__builtin_ia32_sqrtps512_mask" | "__builtin_ia32_sqrtpd512_mask"
+                => {
+                    // TODO: refactor by separating those intrinsics outside of this branch.
+                    let add_before_last_arg =
+                        match &*func_name {
+                            "__builtin_ia32_maxps512_mask" | "__builtin_ia32_maxpd512_mask"
+                                | "__builtin_ia32_minps512_mask" | "__builtin_ia32_minpd512_mask"
+                                | "__builtin_ia32_sqrtps512_mask" | "__builtin_ia32_sqrtpd512_mask" => true,
+                            _ => false,
+                        };
+                    let new_first_arg_is_zero =
+                        match &*func_name {
+                            "__builtin_ia32_pmaxuq256_mask" | "__builtin_ia32_pmaxuq128_mask"
+                                | "__builtin_ia32_pminuq256_mask" | "__builtin_ia32_pminuq128_mask" => true,
+                            _ => false
+                        };
+                    let arg3_index =
+                        match &*func_name {
+                            "__builtin_ia32_sqrtps512_mask" | "__builtin_ia32_sqrtpd512_mask" => 1,
+                            _ => 2,
+                        };
+                    let mut new_args = args.to_vec();
+                    let arg3_type = gcc_func.get_param_type(arg3_index);
+                    let first_arg =
+                        if new_first_arg_is_zero {
+                            let vector_type = arg3_type.dyncast_vector().expect("vector type");
+                            let zero = builder.context.new_rvalue_zero(vector_type.get_element_type());
+                            let num_units = vector_type.get_num_units();
+                            builder.context.new_rvalue_from_vector(None, arg3_type, &vec![zero; num_units])
+                        }
+                        else {
+                            builder.current_func().new_local(None, arg3_type, "undefined_for_intrinsic").to_rvalue()
+                        };
+                    if add_before_last_arg {
+                        new_args.insert(new_args.len() - 1, first_arg);
+                    }
+                    else {
+                        new_args.push(first_arg);
+                    }
+                    let arg4_index =
+                        match &*func_name {
+                            "__builtin_ia32_sqrtps512_mask" | "__builtin_ia32_sqrtpd512_mask" => 2,
+                            _ => 3,
+                        };
+                    let arg4_type = gcc_func.get_param_type(arg4_index);
+                    let minus_one = builder.context.new_rvalue_from_int(arg4_type, -1);
+                    if add_before_last_arg {
+                        new_args.insert(new_args.len() - 1, minus_one);
+                    }
+                    else {
+                        new_args.push(minus_one);
+                    }
+                    args = new_args.into();
+                },
+                "__builtin_ia32_pternlogd512_mask" | "__builtin_ia32_pternlogd256_mask"
+                    | "__builtin_ia32_pternlogd128_mask" | "__builtin_ia32_pternlogq512_mask"
+                    | "__builtin_ia32_pternlogq256_mask" | "__builtin_ia32_pternlogq128_mask" => {
+                        let mut new_args = args.to_vec();
+                        let arg5_type = gcc_func.get_param_type(4);
+                        let minus_one = builder.context.new_rvalue_from_int(arg5_type, -1);
+                        new_args.push(minus_one);
+                        args = new_args.into();
+                    },
+                    "__builtin_ia32_vfmaddps512_mask" | "__builtin_ia32_vfmaddpd512_mask" => {
+                        let mut new_args = args.to_vec();
+
+                        let mut last_arg = None;
+                        if args.len() == 4 {
+                            last_arg = new_args.pop();
+                        }
+
+                        let arg4_type = gcc_func.get_param_type(3);
+                        let minus_one = builder.context.new_rvalue_from_int(arg4_type, -1);
+                        new_args.push(minus_one);
+
+                        if args.len() == 3 {
+                            // Both llvm.fma.v16f32 and llvm.x86.avx512.vfmadd.ps.512 maps to
+                            // the same GCC intrinsic, but the former has 3 parameters and the
+                            // latter has 4 so it doesn't require this additional argument.
+                            let arg5_type = gcc_func.get_param_type(4);
+                            new_args.push(builder.context.new_rvalue_from_int(arg5_type, 4));
+                        }
+
+                        if let Some(last_arg) = last_arg {
+                            new_args.push(last_arg);
+                        }
+
+                        args = new_args.into();
+                    },
+                    "__builtin_ia32_addps512_mask" | "__builtin_ia32_addpd512_mask"
+                        | "__builtin_ia32_subps512_mask" | "__builtin_ia32_subpd512_mask"
+                        | "__builtin_ia32_mulps512_mask" | "__builtin_ia32_mulpd512_mask"
+                        | "__builtin_ia32_divps512_mask" | "__builtin_ia32_divpd512_mask" => {
+                        let mut new_args = args.to_vec();
+                        let last_arg = new_args.pop().expect("last arg");
+                        let arg3_type = gcc_func.get_param_type(2);
+                        let undefined = builder.current_func().new_local(None, arg3_type, "undefined_for_intrinsic").to_rvalue();
+                        new_args.push(undefined);
+                        let arg4_type = gcc_func.get_param_type(3);
+                        let minus_one = builder.context.new_rvalue_from_int(arg4_type, -1);
+                        new_args.push(minus_one);
+                        new_args.push(last_arg);
+                        args = new_args.into();
+                    },
+                    "__builtin_ia32_vfmaddsubps512_mask" | "__builtin_ia32_vfmaddsubpd512_mask" => {
+                        let mut new_args = args.to_vec();
+                        let last_arg = new_args.pop().expect("last arg");
+                        let arg4_type = gcc_func.get_param_type(3);
+                        let minus_one = builder.context.new_rvalue_from_int(arg4_type, -1);
+                        new_args.push(minus_one);
+                        new_args.push(last_arg);
+                        args = new_args.into();
+                    },
+                    _ => (),
+        }
+    }
+
+    args
+}
+
+pub fn ignore_arg_cast(func_name: &str, index: usize, args_len: usize) -> bool {
+    // NOTE: these intrinsics have missing parameters before the last one, so ignore the
+    // last argument type check.
+    // FIXME(antoyo): find a way to refactor in order to avoid this hack.
+    match func_name {
+        "__builtin_ia32_maxps512_mask" | "__builtin_ia32_maxpd512_mask"
+            | "__builtin_ia32_minps512_mask" | "__builtin_ia32_minpd512_mask" | "__builtin_ia32_sqrtps512_mask"
+            | "__builtin_ia32_sqrtpd512_mask" | "__builtin_ia32_addps512_mask" | "__builtin_ia32_addpd512_mask"
+            | "__builtin_ia32_subps512_mask" | "__builtin_ia32_subpd512_mask"
+            | "__builtin_ia32_mulps512_mask" | "__builtin_ia32_mulpd512_mask"
+            | "__builtin_ia32_divps512_mask" | "__builtin_ia32_divpd512_mask"
+            | "__builtin_ia32_vfmaddsubps512_mask" | "__builtin_ia32_vfmaddsubpd512_mask" => {
+                if index == args_len - 1 {
+                    return true;
+                }
             },
-            // NOTE: this doc specifies the equivalent GCC builtins: http://huonw.github.io/llvmint/llvmint/x86/index.html
-            "llvm.x86.sse2.cmp.pd" => "__builtin_ia32_cmppd",
-            "llvm.x86.sse2.movmsk.pd" => "__builtin_ia32_movmskpd",
-            "llvm.x86.sse2.pmovmskb.128" => "__builtin_ia32_pmovmskb128",
-            _ => unimplemented!("unsupported LLVM intrinsic {}", name)
-        };
+        "__builtin_ia32_vfmaddps512_mask" | "__builtin_ia32_vfmaddpd512_mask" => {
+            // Since there are two LLVM intrinsics that map to each of these GCC builtins and only
+            // one of them has a missing parameter before the last one, we check the number of
+            // arguments to distinguish those cases.
+            if args_len == 4 && index == args_len - 1 {
+                return true;
+            }
+        },
+        _ => (),
+    }
 
-    unimplemented!();
+    false
+}
+
+#[cfg(not(feature="master"))]
+pub fn intrinsic<'gcc, 'tcx>(name: &str, cx: &CodegenCx<'gcc, 'tcx>) -> Function<'gcc> {
+    match name {
+        "llvm.x86.xgetbv" => {
+            let gcc_name = "__builtin_trap";
+            let func = cx.context.get_builtin_function(gcc_name);
+            cx.functions.borrow_mut().insert(gcc_name.to_string(), func);
+            return func;
+        },
+        _ => unimplemented!("unsupported LLVM intrinsic {}", name),
+    }
+}
+
+#[cfg(feature="master")]
+pub fn intrinsic<'gcc, 'tcx>(name: &str, cx: &CodegenCx<'gcc, 'tcx>) -> Function<'gcc> {
+    let gcc_name = match name {
+        "llvm.x86.xgetbv" => "__builtin_ia32_xgetbv",
+        // NOTE: this doc specifies the equivalent GCC builtins: http://huonw.github.io/llvmint/llvmint/x86/index.html
+        "llvm.sqrt.v2f64" => "__builtin_ia32_sqrtpd",
+        "llvm.x86.avx512.pmul.dq.512" => "__builtin_ia32_pmuldq512_mask",
+        "llvm.x86.avx512.pmulu.dq.512" => "__builtin_ia32_pmuludq512_mask",
+        "llvm.x86.avx512.mask.pmaxs.q.256" => "__builtin_ia32_pmaxsq256_mask",
+        "llvm.x86.avx512.mask.pmaxs.q.128" => "__builtin_ia32_pmaxsq128_mask",
+        "llvm.x86.avx512.max.ps.512" => "__builtin_ia32_maxps512_mask",
+        "llvm.x86.avx512.max.pd.512" => "__builtin_ia32_maxpd512_mask",
+        "llvm.x86.avx512.mask.pmaxu.q.256" => "__builtin_ia32_pmaxuq256_mask",
+        "llvm.x86.avx512.mask.pmaxu.q.128" => "__builtin_ia32_pmaxuq128_mask",
+        "llvm.x86.avx512.mask.pmins.q.256" => "__builtin_ia32_pminsq256_mask",
+        "llvm.x86.avx512.mask.pmins.q.128" => "__builtin_ia32_pminsq128_mask",
+        "llvm.x86.avx512.min.ps.512" => "__builtin_ia32_minps512_mask",
+        "llvm.x86.avx512.min.pd.512" => "__builtin_ia32_minpd512_mask",
+        "llvm.x86.avx512.mask.pminu.q.256" => "__builtin_ia32_pminuq256_mask",
+        "llvm.x86.avx512.mask.pminu.q.128" => "__builtin_ia32_pminuq128_mask",
+        "llvm.fma.v16f32" => "__builtin_ia32_vfmaddps512_mask",
+        "llvm.fma.v8f64" => "__builtin_ia32_vfmaddpd512_mask",
+        "llvm.x86.avx512.vfmaddsub.ps.512" => "__builtin_ia32_vfmaddsubps512_mask",
+        "llvm.x86.avx512.vfmaddsub.pd.512" => "__builtin_ia32_vfmaddsubpd512_mask",
+        "llvm.x86.avx512.pternlog.d.512" => "__builtin_ia32_pternlogd512_mask",
+        "llvm.x86.avx512.pternlog.d.256" => "__builtin_ia32_pternlogd256_mask",
+        "llvm.x86.avx512.pternlog.d.128" => "__builtin_ia32_pternlogd128_mask",
+        "llvm.x86.avx512.pternlog.q.512" => "__builtin_ia32_pternlogq512_mask",
+        "llvm.x86.avx512.pternlog.q.256" => "__builtin_ia32_pternlogq256_mask",
+        "llvm.x86.avx512.pternlog.q.128" => "__builtin_ia32_pternlogq128_mask",
+        "llvm.x86.avx512.add.ps.512" => "__builtin_ia32_addps512_mask",
+        "llvm.x86.avx512.add.pd.512" => "__builtin_ia32_addpd512_mask",
+        "llvm.x86.avx512.sub.ps.512" => "__builtin_ia32_subps512_mask",
+        "llvm.x86.avx512.sub.pd.512" => "__builtin_ia32_subpd512_mask",
+        "llvm.x86.avx512.mul.ps.512" => "__builtin_ia32_mulps512_mask",
+        "llvm.x86.avx512.mul.pd.512" => "__builtin_ia32_mulpd512_mask",
+        "llvm.x86.avx512.div.ps.512" => "__builtin_ia32_divps512_mask",
+        "llvm.x86.avx512.div.pd.512" => "__builtin_ia32_divpd512_mask",
+        "llvm.x86.avx512.vfmadd.ps.512" => "__builtin_ia32_vfmaddps512_mask",
+        "llvm.x86.avx512.vfmadd.pd.512" => "__builtin_ia32_vfmaddpd512_mask",
+
+        // The above doc points to unknown builtins for the following, so override them:
+        "llvm.x86.avx2.gather.d.d" => "__builtin_ia32_gathersiv4si",
+        "llvm.x86.avx2.gather.d.d.256" => "__builtin_ia32_gathersiv8si",
+        "llvm.x86.avx2.gather.d.ps" => "__builtin_ia32_gathersiv4sf",
+        "llvm.x86.avx2.gather.d.ps.256" => "__builtin_ia32_gathersiv8sf",
+        "llvm.x86.avx2.gather.d.q" => "__builtin_ia32_gathersiv2di",
+        "llvm.x86.avx2.gather.d.q.256" => "__builtin_ia32_gathersiv4di",
+        "llvm.x86.avx2.gather.d.pd" => "__builtin_ia32_gathersiv2df",
+        "llvm.x86.avx2.gather.d.pd.256" => "__builtin_ia32_gathersiv4df",
+        "llvm.x86.avx2.gather.q.d" => "__builtin_ia32_gatherdiv4si",
+        "llvm.x86.avx2.gather.q.d.256" => "__builtin_ia32_gatherdiv4si256",
+        "llvm.x86.avx2.gather.q.ps" => "__builtin_ia32_gatherdiv4sf",
+        "llvm.x86.avx2.gather.q.ps.256" => "__builtin_ia32_gatherdiv4sf256",
+        "llvm.x86.avx2.gather.q.q" => "__builtin_ia32_gatherdiv2di",
+        "llvm.x86.avx2.gather.q.q.256" => "__builtin_ia32_gatherdiv4di",
+        "llvm.x86.avx2.gather.q.pd" => "__builtin_ia32_gatherdiv2df",
+        "llvm.x86.avx2.gather.q.pd.256" => "__builtin_ia32_gatherdiv4df",
+        "" => "",
+        // NOTE: this file is generated by https://github.com/GuillaumeGomez/llvmint/blob/master/generate_list.py
+        _ => include!("archs.rs"),
+    };
+
+    let func = cx.context.get_target_builtin_function(gcc_name);
+    cx.functions.borrow_mut().insert(gcc_name.to_string(), func);
+    func
 }
diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
index 68a05d9..5fbdeda 100644
--- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
+++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
@@ -356,6 +356,16 @@
         self.context.new_rvalue_from_int(self.int_type, 0)
     }
 
+    fn type_checked_load(
+        &mut self,
+        _llvtable: Self::Value,
+        _vtable_byte_offset: u64,
+        _typeid: Self::Value,
+    ) -> Self::Value {
+        // Unsupported.
+        self.context.new_rvalue_from_int(self.int_type, 0)
+    }
+
     fn va_start(&mut self, _va_list: RValue<'gcc>) -> RValue<'gcc> {
         unimplemented!();
     }
@@ -967,34 +977,55 @@
     }
 
     fn saturating_add(&mut self, lhs: RValue<'gcc>, rhs: RValue<'gcc>, signed: bool, width: u64) -> RValue<'gcc> {
-        let func = self.current_func.borrow().expect("func");
-
+        let result_type = lhs.get_type();
         if signed {
-            // Algorithm from: https://stackoverflow.com/a/56531252/389119
-            let after_block = func.new_block("after");
-            let func_name =
-                match width {
-                    8 => "__builtin_add_overflow",
-                    16 => "__builtin_add_overflow",
-                    32 => "__builtin_sadd_overflow",
-                    64 => "__builtin_saddll_overflow",
-                    128 => "__builtin_add_overflow",
-                    _ => unreachable!(),
-                };
-            let overflow_func = self.context.get_builtin_function(func_name);
-            let result_type = lhs.get_type();
+            // Based on algorithm from: https://stackoverflow.com/a/56531252/389119
+            let func = self.current_func.borrow().expect("func");
             let res = func.new_local(None, result_type, "saturating_sum");
-            let overflow = self.overflow_call(overflow_func, &[lhs, rhs, res.get_address(None)], None);
+            let supports_native_type = self.is_native_int_type(result_type);
+            let overflow =
+                if supports_native_type {
+                    let func_name =
+                        match width {
+                            8 => "__builtin_add_overflow",
+                            16 => "__builtin_add_overflow",
+                            32 => "__builtin_sadd_overflow",
+                            64 => "__builtin_saddll_overflow",
+                            128 => "__builtin_add_overflow",
+                            _ => unreachable!(),
+                        };
+                    let overflow_func = self.context.get_builtin_function(func_name);
+                    self.overflow_call(overflow_func, &[lhs, rhs, res.get_address(None)], None)
+                }
+                else {
+                    let func_name =
+                        match width {
+                            128 => "__rust_i128_addo",
+                            _ => unreachable!(),
+                        };
+                    let param_a = self.context.new_parameter(None, result_type, "a");
+                    let param_b = self.context.new_parameter(None, result_type, "b");
+                    let result_field = self.context.new_field(None, result_type, "result");
+                    let overflow_field = self.context.new_field(None, self.bool_type, "overflow");
+                    let return_type = self.context.new_struct_type(None, "result_overflow", &[result_field, overflow_field]);
+                    let func = self.context.new_function(None, FunctionType::Extern, return_type.as_type(), &[param_a, param_b], func_name, false);
+                    let result = self.context.new_call(None, func, &[lhs, rhs]);
+                    let overflow = result.access_field(None, overflow_field);
+                    let int_result = result.access_field(None, result_field);
+                    self.llbb().add_assignment(None, res, int_result);
+                    overflow
+                };
 
             let then_block = func.new_block("then");
+            let after_block = func.new_block("after");
 
-            let unsigned_type = self.context.new_int_type(width as i32 / 8, false);
-            let shifted = self.context.new_cast(None, lhs, unsigned_type) >> self.context.new_rvalue_from_int(unsigned_type, width as i32 - 1);
-            let uint_max = self.context.new_unary_op(None, UnaryOp::BitwiseNegate, unsigned_type,
-                self.context.new_rvalue_from_int(unsigned_type, 0)
-            );
-            let int_max = uint_max >> self.context.new_rvalue_one(unsigned_type);
-            then_block.add_assignment(None, res, self.context.new_cast(None, shifted + int_max, result_type));
+            // Return `result_type`'s maximum or minimum value on overflow
+            // NOTE: convert the type to unsigned to have an unsigned shift.
+            let unsigned_type = result_type.to_unsigned(&self.cx);
+            let shifted = self.gcc_lshr(self.gcc_int_cast(lhs, unsigned_type), self.gcc_int(unsigned_type, width as i64 - 1));
+            let uint_max = self.gcc_not(self.gcc_int(unsigned_type, 0));
+            let int_max = self.gcc_lshr(uint_max, self.gcc_int(unsigned_type, 1));
+            then_block.add_assignment(None, res, self.gcc_int_cast(self.gcc_add(shifted, int_max), result_type));
             then_block.end_with_jump(None, after_block);
 
             self.llbb().end_with_conditional(None, overflow, then_block, after_block);
@@ -1007,19 +1038,18 @@
         }
         else {
             // Algorithm from: http://locklessinc.com/articles/sat_arithmetic/
-            let res = lhs + rhs;
-            let res_type = res.get_type();
-            let cond = self.context.new_comparison(None, ComparisonOp::LessThan, res, lhs);
-            let value = self.context.new_unary_op(None, UnaryOp::Minus, res_type, self.context.new_cast(None, cond, res_type));
-            res | value
+            let res = self.gcc_add(lhs, rhs);
+            let cond = self.gcc_icmp(IntPredicate::IntULT, res, lhs);
+            let value = self.gcc_neg(self.gcc_int_cast(cond, result_type));
+            self.gcc_or(res, value)
         }
     }
 
     // Algorithm from: https://locklessinc.com/articles/sat_arithmetic/
     fn saturating_sub(&mut self, lhs: RValue<'gcc>, rhs: RValue<'gcc>, signed: bool, width: u64) -> RValue<'gcc> {
+        let result_type = lhs.get_type();
         if signed {
-            // Also based on algorithm from: https://stackoverflow.com/a/56531252/389119
-            let result_type = lhs.get_type();
+            // Based on algorithm from: https://stackoverflow.com/a/56531252/389119
             let func = self.current_func.borrow().expect("func");
             let res = func.new_local(None, result_type, "saturating_diff");
             let supports_native_type = self.is_native_int_type(result_type);
@@ -1059,6 +1089,7 @@
             let then_block = func.new_block("then");
             let after_block = func.new_block("after");
 
+            // Return `result_type`'s maximum or minimum value on overflow
             // NOTE: convert the type to unsigned to have an unsigned shift.
             let unsigned_type = result_type.to_unsigned(&self.cx);
             let shifted = self.gcc_lshr(self.gcc_int_cast(lhs, unsigned_type), self.gcc_int(unsigned_type, width as i64 - 1));
@@ -1076,11 +1107,10 @@
             res.to_rvalue()
         }
         else {
-            let res = lhs - rhs;
-            let comparison = self.context.new_comparison(None, ComparisonOp::LessThanEquals, res, lhs);
-            let comparison = self.context.new_cast(None, comparison, lhs.get_type());
-            let unary_op = self.context.new_unary_op(None, UnaryOp::Minus, comparison.get_type(), comparison);
-            self.and(res, unary_op)
+            let res = self.gcc_sub(lhs, rhs);
+            let comparison = self.gcc_icmp(IntPredicate::IntULE, res, lhs);
+            let value = self.gcc_neg(self.gcc_int_cast(comparison, result_type));
+            self.gcc_and(res, value)
         }
     }
 }
diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs
index 7d7811c..2401f33 100644
--- a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs
+++ b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs
@@ -1,18 +1,24 @@
-use gccjit::{RValue, Type};
+use std::cmp::Ordering;
+
+use gccjit::{BinaryOp, RValue, Type, ToRValue};
 use rustc_codegen_ssa::base::compare_simd_types;
 use rustc_codegen_ssa::common::{TypeKind, span_invalid_monomorphization_error};
 use rustc_codegen_ssa::mir::operand::OperandRef;
+use rustc_codegen_ssa::mir::place::PlaceRef;
 use rustc_codegen_ssa::traits::{BaseTypeMethods, BuilderMethods};
 use rustc_hir as hir;
 use rustc_middle::span_bug;
 use rustc_middle::ty::layout::HasTyCtxt;
 use rustc_middle::ty::{self, Ty};
 use rustc_span::{Span, Symbol, sym};
+use rustc_target::abi::Align;
 
 use crate::builder::Builder;
+use crate::intrinsic;
 
 pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>, name: Symbol, callee_ty: Ty<'tcx>, args: &[OperandRef<'tcx, RValue<'gcc>>], ret_ty: Ty<'tcx>, llret_ty: Type<'gcc>, span: Span) -> Result<RValue<'gcc>, ()> {
     // macros for error handling:
+    #[allow(unused_macro_rules)]
     macro_rules! emit_error {
         ($msg: tt) => {
             emit_error!($msg, )
@@ -52,7 +58,53 @@
     let sig =
         tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), callee_ty.fn_sig(tcx));
     let arg_tys = sig.inputs();
-    let name_str = name.as_str();
+
+    if name == sym::simd_select_bitmask {
+        require_simd!(arg_tys[1], "argument");
+        let (len, _) = arg_tys[1].simd_size_and_type(bx.tcx());
+
+        let expected_int_bits = (len.max(8) - 1).next_power_of_two();
+        let expected_bytes = len / 8 + ((len % 8 > 0) as u64);
+
+        let mask_ty = arg_tys[0];
+        let mut mask = match mask_ty.kind() {
+            ty::Int(i) if i.bit_width() == Some(expected_int_bits) => args[0].immediate(),
+            ty::Uint(i) if i.bit_width() == Some(expected_int_bits) => args[0].immediate(),
+            ty::Array(elem, len)
+                if matches!(elem.kind(), ty::Uint(ty::UintTy::U8))
+                    && len.try_eval_usize(bx.tcx, ty::ParamEnv::reveal_all())
+                        == Some(expected_bytes) =>
+            {
+                let place = PlaceRef::alloca(bx, args[0].layout);
+                args[0].val.store(bx, place);
+                let int_ty = bx.type_ix(expected_bytes * 8);
+                let ptr = bx.pointercast(place.llval, bx.cx.type_ptr_to(int_ty));
+                bx.load(int_ty, ptr, Align::ONE)
+            }
+            _ => return_error!(
+                "invalid bitmask `{}`, expected `u{}` or `[u8; {}]`",
+                mask_ty,
+                expected_int_bits,
+                expected_bytes
+            ),
+        };
+
+        let arg1 = args[1].immediate();
+        let arg1_type = arg1.get_type();
+        let arg1_vector_type = arg1_type.unqualified().dyncast_vector().expect("vector type");
+        let arg1_element_type = arg1_vector_type.get_element_type();
+
+        let mut elements = vec![];
+        let one = bx.context.new_rvalue_one(mask.get_type());
+        for _ in 0..len {
+            let element = bx.context.new_cast(None, mask & one, arg1_element_type);
+            elements.push(element);
+            mask = mask >> one;
+        }
+        let vector_mask = bx.context.new_rvalue_from_vector(None, arg1_type, &elements);
+
+        return Ok(bx.vector_select(vector_mask, arg1, args[2].immediate()));
+    }
 
     // every intrinsic below takes a SIMD vector as its first argument
     require_simd!(arg_tys[0], "input");
@@ -99,10 +151,28 @@
         ));
     }
 
-    if let Some(stripped) = name_str.strip_prefix("simd_shuffle") {
-        let n: u64 = stripped.parse().unwrap_or_else(|_| {
-            span_bug!(span, "bad `simd_shuffle` instruction only caught in codegen?")
-        });
+    if let Some(stripped) = name.as_str().strip_prefix("simd_shuffle") {
+        let n: u64 =
+            if stripped.is_empty() {
+                // Make sure this is actually an array, since typeck only checks the length-suffixed
+                // version of this intrinsic.
+                match args[2].layout.ty.kind() {
+                    ty::Array(ty, len) if matches!(ty.kind(), ty::Uint(ty::UintTy::U32)) => {
+                        len.try_eval_usize(bx.cx.tcx, ty::ParamEnv::reveal_all()).unwrap_or_else(|| {
+                            span_bug!(span, "could not evaluate shuffle index array length")
+                        })
+                    }
+                    _ => return_error!(
+                        "simd_shuffle index must be an array of `u32`, got `{}`",
+                        args[2].layout.ty
+                    ),
+                }
+            }
+            else {
+                stripped.parse().unwrap_or_else(|_| {
+                    span_bug!(span, "bad `simd_shuffle` instruction only caught in codegen?")
+                })
+            };
 
         require_simd!(ret_ty, "return");
 
@@ -133,6 +203,225 @@
         ));
     }
 
+    #[cfg(feature="master")]
+    if name == sym::simd_insert {
+        require!(
+            in_elem == arg_tys[2],
+            "expected inserted type `{}` (element of input `{}`), found `{}`",
+            in_elem,
+            in_ty,
+            arg_tys[2]
+        );
+        let vector = args[0].immediate();
+        let index = args[1].immediate();
+        let value = args[2].immediate();
+        // TODO(antoyo): use a recursive unqualified() here.
+        let vector_type = vector.get_type().unqualified().dyncast_vector().expect("vector type");
+        let element_type = vector_type.get_element_type();
+        // NOTE: we cannot cast to an array and assign to its element here because the value might
+        // not be an l-value. So, call a builtin to set the element.
+        // TODO(antoyo): perhaps we could create a new vector or maybe there's a GIMPLE instruction for that?
+        // TODO(antoyo): don't use target specific builtins here.
+        let func_name =
+            match in_len {
+                2 => {
+                    if element_type == bx.i64_type {
+                        "__builtin_ia32_vec_set_v2di"
+                    }
+                    else {
+                        unimplemented!();
+                    }
+                },
+                4 => {
+                    if element_type == bx.i32_type {
+                        "__builtin_ia32_vec_set_v4si"
+                    }
+                    else {
+                        unimplemented!();
+                    }
+                },
+                8 => {
+                    if element_type == bx.i16_type {
+                        "__builtin_ia32_vec_set_v8hi"
+                    }
+                    else {
+                        unimplemented!();
+                    }
+                },
+                _ => unimplemented!("Len: {}", in_len),
+            };
+        let builtin = bx.context.get_target_builtin_function(func_name);
+        let param1_type = builtin.get_param(0).to_rvalue().get_type();
+        // TODO(antoyo): perhaps use __builtin_convertvector for vector casting.
+        let vector = bx.cx.bitcast_if_needed(vector, param1_type);
+        let result = bx.context.new_call(None, builtin, &[vector, value, bx.context.new_cast(None, index, bx.int_type)]);
+        // TODO(antoyo): perhaps use __builtin_convertvector for vector casting.
+        return Ok(bx.context.new_bitcast(None, result, vector.get_type()));
+    }
+
+    #[cfg(feature="master")]
+    if name == sym::simd_extract {
+        require!(
+            ret_ty == in_elem,
+            "expected return type `{}` (element of input `{}`), found `{}`",
+            in_elem,
+            in_ty,
+            ret_ty
+        );
+        let vector = args[0].immediate();
+        return Ok(bx.context.new_vector_access(None, vector, args[1].immediate()).to_rvalue());
+    }
+
+    if name == sym::simd_select {
+        let m_elem_ty = in_elem;
+        let m_len = in_len;
+        require_simd!(arg_tys[1], "argument");
+        let (v_len, _) = arg_tys[1].simd_size_and_type(bx.tcx());
+        require!(
+            m_len == v_len,
+            "mismatched lengths: mask length `{}` != other vector length `{}`",
+            m_len,
+            v_len
+        );
+        match m_elem_ty.kind() {
+            ty::Int(_) => {}
+            _ => return_error!("mask element type is `{}`, expected `i_`", m_elem_ty),
+        }
+        return Ok(bx.vector_select(args[0].immediate(), args[1].immediate(), args[2].immediate()));
+    }
+
+    if name == sym::simd_cast {
+        require_simd!(ret_ty, "return");
+        let (out_len, out_elem) = ret_ty.simd_size_and_type(bx.tcx());
+        require!(
+            in_len == out_len,
+            "expected return type with length {} (same as input type `{}`), \
+                  found `{}` with length {}",
+            in_len,
+            in_ty,
+            ret_ty,
+            out_len
+        );
+        // casting cares about nominal type, not just structural type
+        if in_elem == out_elem {
+            return Ok(args[0].immediate());
+        }
+
+        enum Style {
+            Float,
+            Int(/* is signed? */ bool),
+            Unsupported,
+        }
+
+        let (in_style, in_width) = match in_elem.kind() {
+            // vectors of pointer-sized integers should've been
+            // disallowed before here, so this unwrap is safe.
+            ty::Int(i) => (
+                Style::Int(true),
+                i.normalize(bx.tcx().sess.target.pointer_width).bit_width().unwrap(),
+            ),
+            ty::Uint(u) => (
+                Style::Int(false),
+                u.normalize(bx.tcx().sess.target.pointer_width).bit_width().unwrap(),
+            ),
+            ty::Float(f) => (Style::Float, f.bit_width()),
+            _ => (Style::Unsupported, 0),
+        };
+        let (out_style, out_width) = match out_elem.kind() {
+            ty::Int(i) => (
+                Style::Int(true),
+                i.normalize(bx.tcx().sess.target.pointer_width).bit_width().unwrap(),
+            ),
+            ty::Uint(u) => (
+                Style::Int(false),
+                u.normalize(bx.tcx().sess.target.pointer_width).bit_width().unwrap(),
+            ),
+            ty::Float(f) => (Style::Float, f.bit_width()),
+            _ => (Style::Unsupported, 0),
+        };
+
+        let extend = |in_type, out_type| {
+            let vector_type = bx.context.new_vector_type(out_type, 8);
+            let vector = args[0].immediate();
+            let array_type = bx.context.new_array_type(None, in_type, 8);
+            // TODO(antoyo): switch to using new_vector_access or __builtin_convertvector for vector casting.
+            let array = bx.context.new_bitcast(None, vector, array_type);
+
+            let cast_vec_element = |index| {
+                let index = bx.context.new_rvalue_from_int(bx.int_type, index);
+                bx.context.new_cast(None, bx.context.new_array_access(None, array, index).to_rvalue(), out_type)
+            };
+
+            bx.context.new_rvalue_from_vector(None, vector_type, &[
+                cast_vec_element(0),
+                cast_vec_element(1),
+                cast_vec_element(2),
+                cast_vec_element(3),
+                cast_vec_element(4),
+                cast_vec_element(5),
+                cast_vec_element(6),
+                cast_vec_element(7),
+            ])
+        };
+
+        match (in_style, out_style) {
+            (Style::Int(in_is_signed), Style::Int(_)) => {
+                return Ok(match in_width.cmp(&out_width) {
+                    Ordering::Greater => bx.trunc(args[0].immediate(), llret_ty),
+                    Ordering::Equal => args[0].immediate(),
+                    Ordering::Less => {
+                        if in_is_signed {
+                            match (in_width, out_width) {
+                                // FIXME(antoyo): the function _mm_cvtepi8_epi16 should directly
+                                // call an intrinsic equivalent to __builtin_ia32_pmovsxbw128 so that
+                                // we can generate a call to it.
+                                (8, 16) => extend(bx.i8_type, bx.i16_type),
+                                (8, 32) => extend(bx.i8_type, bx.i32_type),
+                                (8, 64) => extend(bx.i8_type, bx.i64_type),
+                                (16, 32) => extend(bx.i16_type, bx.i32_type),
+                                (32, 64) => extend(bx.i32_type, bx.i64_type),
+                                (16, 64) => extend(bx.i16_type, bx.i64_type),
+                                _ => unimplemented!("in: {}, out: {}", in_width, out_width),
+                            }
+                        } else {
+                            match (in_width, out_width) {
+                                (8, 16) => extend(bx.u8_type, bx.u16_type),
+                                (8, 32) => extend(bx.u8_type, bx.u32_type),
+                                (8, 64) => extend(bx.u8_type, bx.u64_type),
+                                (16, 32) => extend(bx.u16_type, bx.u32_type),
+                                (16, 64) => extend(bx.u16_type, bx.u64_type),
+                                (32, 64) => extend(bx.u32_type, bx.u64_type),
+                                _ => unimplemented!("in: {}, out: {}", in_width, out_width),
+                            }
+                        }
+                    }
+                });
+            }
+            (Style::Int(_), Style::Float) => {
+                // TODO: add support for internal functions in libgccjit to get access to IFN_VEC_CONVERT which is
+                // doing like __builtin_convertvector?
+                // Or maybe provide convert_vector as an API since it might not easy to get the
+                // types of internal functions.
+                unimplemented!();
+            }
+            (Style::Float, Style::Int(_)) => {
+                unimplemented!();
+            }
+            (Style::Float, Style::Float) => {
+                unimplemented!();
+            }
+            _ => { /* Unsupported. Fallthrough. */ }
+        }
+        require!(
+            false,
+            "unsupported cast from `{}` with element `{}` to `{}` with element `{}`",
+            in_ty,
+            in_elem,
+            ret_ty,
+            out_elem
+        );
+    }
+
     macro_rules! arith_binary {
         ($($name: ident: $($($p: ident),* => $call: ident),*;)*) => {
             $(if name == sym::$name {
@@ -150,6 +439,102 @@
         }
     }
 
+    fn simd_simple_float_intrinsic<'gcc, 'tcx>(
+        name: Symbol,
+        in_elem: Ty<'_>,
+        in_ty: Ty<'_>,
+        in_len: u64,
+        bx: &mut Builder<'_, 'gcc, 'tcx>,
+        span: Span,
+        args: &[OperandRef<'tcx, RValue<'gcc>>],
+    ) -> Result<RValue<'gcc>, ()> {
+        macro_rules! emit_error {
+            ($msg: tt, $($fmt: tt)*) => {
+                span_invalid_monomorphization_error(
+                    bx.sess(), span,
+                    &format!(concat!("invalid monomorphization of `{}` intrinsic: ", $msg),
+                             name, $($fmt)*));
+            }
+        }
+        macro_rules! return_error {
+            ($($fmt: tt)*) => {
+                {
+                    emit_error!($($fmt)*);
+                    return Err(());
+                }
+            }
+        }
+
+        let (elem_ty_str, elem_ty) =
+            if let ty::Float(f) = in_elem.kind() {
+                let elem_ty = bx.cx.type_float_from_ty(*f);
+                match f.bit_width() {
+                    32 => ("f32", elem_ty),
+                    64 => ("f64", elem_ty),
+                    _ => {
+                        return_error!(
+                            "unsupported element type `{}` of floating-point vector `{}`",
+                            f.name_str(),
+                            in_ty
+                        );
+                    }
+                }
+            }
+            else {
+                return_error!("`{}` is not a floating-point type", in_ty);
+            };
+
+        let vec_ty = bx.cx.type_vector(elem_ty, in_len);
+
+        let (intr_name, fn_ty) =
+            match name {
+                sym::simd_ceil => ("ceil", bx.type_func(&[vec_ty], vec_ty)),
+                sym::simd_fabs => ("fabs", bx.type_func(&[vec_ty], vec_ty)), // TODO(antoyo): pand with 170141183420855150465331762880109871103
+                sym::simd_fcos => ("cos", bx.type_func(&[vec_ty], vec_ty)),
+                sym::simd_fexp2 => ("exp2", bx.type_func(&[vec_ty], vec_ty)),
+                sym::simd_fexp => ("exp", bx.type_func(&[vec_ty], vec_ty)),
+                sym::simd_flog10 => ("log10", bx.type_func(&[vec_ty], vec_ty)),
+                sym::simd_flog2 => ("log2", bx.type_func(&[vec_ty], vec_ty)),
+                sym::simd_flog => ("log", bx.type_func(&[vec_ty], vec_ty)),
+                sym::simd_floor => ("floor", bx.type_func(&[vec_ty], vec_ty)),
+                sym::simd_fma => ("fma", bx.type_func(&[vec_ty, vec_ty, vec_ty], vec_ty)),
+                sym::simd_fpowi => ("powi", bx.type_func(&[vec_ty, bx.type_i32()], vec_ty)),
+                sym::simd_fpow => ("pow", bx.type_func(&[vec_ty, vec_ty], vec_ty)),
+                sym::simd_fsin => ("sin", bx.type_func(&[vec_ty], vec_ty)),
+                sym::simd_fsqrt => ("sqrt", bx.type_func(&[vec_ty], vec_ty)),
+                sym::simd_round => ("round", bx.type_func(&[vec_ty], vec_ty)),
+                sym::simd_trunc => ("trunc", bx.type_func(&[vec_ty], vec_ty)),
+                _ => return_error!("unrecognized intrinsic `{}`", name),
+            };
+        let llvm_name = &format!("llvm.{0}.v{1}{2}", intr_name, in_len, elem_ty_str);
+        let function = intrinsic::llvm::intrinsic(llvm_name, &bx.cx);
+        let function: RValue<'gcc> = unsafe { std::mem::transmute(function) };
+        let c = bx.call(fn_ty, function, &args.iter().map(|arg| arg.immediate()).collect::<Vec<_>>(), None);
+        Ok(c)
+    }
+
+    if std::matches!(
+        name,
+        sym::simd_ceil
+            | sym::simd_fabs
+            | sym::simd_fcos
+            | sym::simd_fexp2
+            | sym::simd_fexp
+            | sym::simd_flog10
+            | sym::simd_flog2
+            | sym::simd_flog
+            | sym::simd_floor
+            | sym::simd_fma
+            | sym::simd_fpow
+            | sym::simd_fpowi
+            | sym::simd_fsin
+            | sym::simd_fsqrt
+            | sym::simd_round
+            | sym::simd_trunc
+    ) {
+        return simd_simple_float_intrinsic(name, in_elem, in_ty, in_len, bx, span, args);
+    }
+
     arith_binary! {
         simd_add: Uint, Int => add, Float => fadd;
         simd_sub: Uint, Int => sub, Float => fsub;
@@ -184,5 +569,183 @@
         simd_neg: Int => neg, Float => fneg;
     }
 
+    #[cfg(feature="master")]
+    if name == sym::simd_saturating_add || name == sym::simd_saturating_sub {
+        let lhs = args[0].immediate();
+        let rhs = args[1].immediate();
+        let is_add = name == sym::simd_saturating_add;
+        let ptr_bits = bx.tcx().data_layout.pointer_size.bits() as _;
+        let (signed, elem_width, elem_ty) = match *in_elem.kind() {
+            ty::Int(i) => (true, i.bit_width().unwrap_or(ptr_bits), bx.cx.type_int_from_ty(i)),
+            ty::Uint(i) => (false, i.bit_width().unwrap_or(ptr_bits), bx.cx.type_uint_from_ty(i)),
+            _ => {
+                return_error!(
+                    "expected element type `{}` of vector type `{}` \
+                     to be a signed or unsigned integer type",
+                    arg_tys[0].simd_size_and_type(bx.tcx()).1,
+                    arg_tys[0]
+                );
+            }
+        };
+        let builtin_name =
+            match (signed, is_add, in_len, elem_width) {
+                (true, true, 32, 8) => "__builtin_ia32_paddsb256", // TODO(antoyo): cast arguments to unsigned.
+                (false, true, 32, 8) => "__builtin_ia32_paddusb256",
+                (true, true, 16, 16) => "__builtin_ia32_paddsw256",
+                (false, true, 16, 16) => "__builtin_ia32_paddusw256",
+                (true, false, 16, 16) => "__builtin_ia32_psubsw256",
+                (false, false, 16, 16) => "__builtin_ia32_psubusw256",
+                (true, false, 32, 8) => "__builtin_ia32_psubsb256",
+                (false, false, 32, 8) => "__builtin_ia32_psubusb256",
+                _ => unimplemented!("signed: {}, is_add: {}, in_len: {}, elem_width: {}", signed, is_add, in_len, elem_width),
+            };
+        let vec_ty = bx.cx.type_vector(elem_ty, in_len as u64);
+
+        let func = bx.context.get_target_builtin_function(builtin_name);
+        let param1_type = func.get_param(0).to_rvalue().get_type();
+        let param2_type = func.get_param(1).to_rvalue().get_type();
+        let lhs = bx.cx.bitcast_if_needed(lhs, param1_type);
+        let rhs = bx.cx.bitcast_if_needed(rhs, param2_type);
+        let result = bx.context.new_call(None, func, &[lhs, rhs]);
+        // TODO(antoyo): perhaps use __builtin_convertvector for vector casting.
+        return Ok(bx.context.new_bitcast(None, result, vec_ty));
+    }
+
+    macro_rules! arith_red {
+        ($name:ident : $vec_op:expr, $float_reduce:ident, $ordered:expr, $op:ident,
+         $identity:expr) => {
+            if name == sym::$name {
+                require!(
+                    ret_ty == in_elem,
+                    "expected return type `{}` (element of input `{}`), found `{}`",
+                    in_elem,
+                    in_ty,
+                    ret_ty
+                );
+                return match in_elem.kind() {
+                    ty::Int(_) | ty::Uint(_) => {
+                        let r = bx.vector_reduce_op(args[0].immediate(), $vec_op);
+                        if $ordered {
+                            // if overflow occurs, the result is the
+                            // mathematical result modulo 2^n:
+                            Ok(bx.$op(args[1].immediate(), r))
+                        }
+                        else {
+                            Ok(bx.vector_reduce_op(args[0].immediate(), $vec_op))
+                        }
+                    }
+                    ty::Float(_) => {
+                        if $ordered {
+                            // ordered arithmetic reductions take an accumulator
+                            let acc = args[1].immediate();
+                            Ok(bx.$float_reduce(acc, args[0].immediate()))
+                        }
+                        else {
+                            Ok(bx.vector_reduce_op(args[0].immediate(), $vec_op))
+                        }
+                    }
+                    _ => return_error!(
+                        "unsupported {} from `{}` with element `{}` to `{}`",
+                        sym::$name,
+                        in_ty,
+                        in_elem,
+                        ret_ty
+                    ),
+                };
+            }
+        };
+    }
+
+    arith_red!(
+        simd_reduce_add_unordered: BinaryOp::Plus,
+        vector_reduce_fadd_fast,
+        false,
+        add,
+        0.0 // TODO: Use this argument.
+    );
+    arith_red!(
+        simd_reduce_mul_unordered: BinaryOp::Mult,
+        vector_reduce_fmul_fast,
+        false,
+        mul,
+        1.0
+    );
+
+    macro_rules! minmax_red {
+        ($name:ident: $reduction:ident) => {
+            if name == sym::$name {
+                require!(
+                    ret_ty == in_elem,
+                    "expected return type `{}` (element of input `{}`), found `{}`",
+                    in_elem,
+                    in_ty,
+                    ret_ty
+                );
+                return match in_elem.kind() {
+                    ty::Int(_) | ty::Uint(_) | ty::Float(_) => Ok(bx.$reduction(args[0].immediate())),
+                    _ => return_error!(
+                        "unsupported {} from `{}` with element `{}` to `{}`",
+                        sym::$name,
+                        in_ty,
+                        in_elem,
+                        ret_ty
+                    ),
+                };
+            }
+        };
+    }
+
+    minmax_red!(simd_reduce_min: vector_reduce_min);
+    minmax_red!(simd_reduce_max: vector_reduce_max);
+
+    macro_rules! bitwise_red {
+        ($name:ident : $op:expr, $boolean:expr) => {
+            if name == sym::$name {
+                let input = if !$boolean {
+                    require!(
+                        ret_ty == in_elem,
+                        "expected return type `{}` (element of input `{}`), found `{}`",
+                        in_elem,
+                        in_ty,
+                        ret_ty
+                    );
+                    args[0].immediate()
+                } else {
+                    match in_elem.kind() {
+                        ty::Int(_) | ty::Uint(_) => {}
+                        _ => return_error!(
+                            "unsupported {} from `{}` with element `{}` to `{}`",
+                            sym::$name,
+                            in_ty,
+                            in_elem,
+                            ret_ty
+                        ),
+                    }
+
+                    // boolean reductions operate on vectors of i1s:
+                    let i1 = bx.type_i1();
+                    let i1xn = bx.type_vector(i1, in_len as u64);
+                    bx.trunc(args[0].immediate(), i1xn)
+                };
+                return match in_elem.kind() {
+                    ty::Int(_) | ty::Uint(_) => {
+                        let r = bx.vector_reduce_op(input, $op);
+                        Ok(if !$boolean { r } else { bx.zext(r, bx.type_bool()) })
+                    }
+                    _ => return_error!(
+                        "unsupported {} from `{}` with element `{}` to `{}`",
+                        sym::$name,
+                        in_ty,
+                        in_elem,
+                        ret_ty
+                    ),
+                };
+            }
+        };
+    }
+
+    bitwise_red!(simd_reduce_and: BinaryOp::BitwiseAnd, false);
+    bitwise_red!(simd_reduce_or: BinaryOp::BitwiseOr, false);
+
     unimplemented!("simd {}", name);
 }
diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs
index 58996a9..5bfdeb8 100644
--- a/compiler/rustc_codegen_gcc/src/lib.rs
+++ b/compiler/rustc_codegen_gcc/src/lib.rs
@@ -203,7 +203,7 @@
     fn run_fat_lto(_cgcx: &CodegenContext<Self>, mut modules: Vec<FatLTOInput<Self>>, _cached_modules: Vec<(SerializedModule<Self::ModuleBuffer>, WorkProduct)>) -> Result<LtoModuleCodegen<Self>, FatalError> {
         // TODO(antoyo): implement LTO by sending -flto to libgccjit and adding the appropriate gcc linker plugins.
         // NOTE: implemented elsewhere.
-        // TODO: what is implemented elsewhere ^ ?
+        // TODO(antoyo): what is implemented elsewhere ^ ?
         let module =
             match modules.remove(0) {
                 FatLTOInput::InMemory(module) => module,
@@ -301,7 +301,22 @@
         )
         .filter(|_feature| {
             // TODO(antoyo): implement a way to get enabled feature in libgccjit.
-            false
+            // Probably using the equivalent of __builtin_cpu_supports.
+            #[cfg(feature="master")]
+            {
+                _feature.contains("sse") || _feature.contains("avx")
+            }
+            #[cfg(not(feature="master"))]
+            {
+                false
+            }
+            /*
+               adx, aes, avx, avx2, avx512bf16, avx512bitalg, avx512bw, avx512cd, avx512dq, avx512er, avx512f, avx512gfni,
+               avx512ifma, avx512pf, avx512vaes, avx512vbmi, avx512vbmi2, avx512vl, avx512vnni, avx512vp2intersect, avx512vpclmulqdq,
+               avx512vpopcntdq, bmi1, bmi2, cmpxchg16b, ermsb, f16c, fma, fxsr, lzcnt, movbe, pclmulqdq, popcnt, rdrand, rdseed, rtm,
+               sha, sse, sse2, sse3, sse4.1, sse4.2, sse4a, ssse3, tbm, xsave, xsavec, xsaveopt, xsaves
+             */
+            //false
         })
         .map(|feature| Symbol::intern(feature))
         .collect()
diff --git a/compiler/rustc_codegen_gcc/src/type_.rs b/compiler/rustc_codegen_gcc/src/type_.rs
index e950580..002b95d 100644
--- a/compiler/rustc_codegen_gcc/src/type_.rs
+++ b/compiler/rustc_codegen_gcc/src/type_.rs
@@ -3,10 +3,11 @@
 use gccjit::{RValue, Struct, Type};
 use rustc_codegen_ssa::traits::{BaseTypeMethods, DerivedTypeMethods};
 use rustc_codegen_ssa::common::TypeKind;
-use rustc_middle::bug;
+use rustc_middle::{bug, ty};
 use rustc_middle::ty::layout::TyAndLayout;
 use rustc_target::abi::{AddressSpace, Align, Integer, Size};
 
+use crate::common::TypeReflection;
 use crate::context::CodegenCx;
 use crate::type_of::LayoutGccExt;
 
@@ -60,6 +61,17 @@
         let ity = Integer::approximate_align(self, align);
         self.type_from_integer(ity)
     }
+
+    pub fn type_vector(&self, ty: Type<'gcc>, len: u64) -> Type<'gcc> {
+        self.context.new_vector_type(ty, len)
+    }
+
+    pub fn type_float_from_ty(&self, t: ty::FloatTy) -> Type<'gcc> {
+        match t {
+            ty::FloatTy::F32 => self.type_f32(),
+            ty::FloatTy::F64 => self.type_f64(),
+        }
+    }
 }
 
 impl<'gcc, 'tcx> BaseTypeMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
@@ -103,7 +115,7 @@
         self.context.new_function_pointer_type(None, return_type, params, false)
     }
 
-    fn type_struct(&self, fields: &[Type<'gcc>], _packed: bool) -> Type<'gcc> {
+    fn type_struct(&self, fields: &[Type<'gcc>], packed: bool) -> Type<'gcc> {
         let types = fields.to_vec();
         if let Some(typ) = self.struct_types.borrow().get(fields) {
             return typ.clone();
@@ -111,8 +123,11 @@
         let fields: Vec<_> = fields.iter().enumerate()
             .map(|(index, field)| self.context.new_field(None, *field, &format!("field{}_TODO", index)))
             .collect();
-        // TODO(antoyo): use packed.
         let typ = self.context.new_struct_type(None, "struct", &fields).as_type();
+        if packed {
+            #[cfg(feature="master")]
+            typ.set_packed();
+        }
         self.struct_types.borrow_mut().insert(types, typ);
         typ
     }
@@ -127,7 +142,7 @@
         else if typ.is_compatible_with(self.double_type) {
             TypeKind::Double
         }
-        else if typ.dyncast_vector().is_some() {
+        else if typ.is_vector() {
             TypeKind::Vector
         }
         else {
@@ -141,7 +156,7 @@
     }
 
     fn type_ptr_to_ext(&self, ty: Type<'gcc>, _address_space: AddressSpace) -> Type<'gcc> {
-        // TODO(antoyo): use address_space
+        // TODO(antoyo): use address_space, perhaps with TYPE_ADDR_SPACE?
         ty.make_pointer()
     }
 
@@ -167,10 +182,10 @@
     fn float_width(&self, typ: Type<'gcc>) -> usize {
         let f32 = self.context.new_type::<f32>();
         let f64 = self.context.new_type::<f64>();
-        if typ == f32 {
+        if typ.is_compatible_with(f32) {
             32
         }
-        else if typ == f64 {
+        else if typ.is_compatible_with(f64) {
             64
         }
         else {
@@ -197,12 +212,15 @@
         self.type_array(self.type_from_integer(unit), size / unit_size)
     }
 
-    pub fn set_struct_body(&self, typ: Struct<'gcc>, fields: &[Type<'gcc>], _packed: bool) {
-        // TODO(antoyo): use packed.
+    pub fn set_struct_body(&self, typ: Struct<'gcc>, fields: &[Type<'gcc>], packed: bool) {
         let fields: Vec<_> = fields.iter().enumerate()
             .map(|(index, field)| self.context.new_field(None, *field, &format!("field_{}", index)))
             .collect();
         typ.set_fields(None, &fields);
+        if packed {
+            #[cfg(feature="master")]
+            typ.as_type().set_packed();
+        }
     }
 
     pub fn type_named_struct(&self, name: &str) -> Struct<'gcc> {
@@ -229,6 +247,10 @@
 
         self.context.new_array_type(None, ty, len)
     }
+
+    pub fn type_bool(&self) -> Type<'gcc> {
+        self.context.new_type::<bool>()
+    }
 }
 
 pub fn struct_fields<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, layout: TyAndLayout<'tcx>) -> (Vec<Type<'gcc>>, bool) {
diff --git a/compiler/rustc_codegen_gcc/src/type_of.rs b/compiler/rustc_codegen_gcc/src/type_of.rs
index 2c042ba..569ee29 100644
--- a/compiler/rustc_codegen_gcc/src/type_of.rs
+++ b/compiler/rustc_codegen_gcc/src/type_of.rs
@@ -24,6 +24,30 @@
             I128 => self.type_u128(),
         }
     }
+
+    #[cfg(feature="master")]
+    pub fn type_int_from_ty(&self, t: ty::IntTy) -> Type<'gcc> {
+        match t {
+            ty::IntTy::Isize => self.type_isize(),
+            ty::IntTy::I8 => self.type_i8(),
+            ty::IntTy::I16 => self.type_i16(),
+            ty::IntTy::I32 => self.type_i32(),
+            ty::IntTy::I64 => self.type_i64(),
+            ty::IntTy::I128 => self.type_i128(),
+        }
+    }
+
+    #[cfg(feature="master")]
+    pub fn type_uint_from_ty(&self, t: ty::UintTy) -> Type<'gcc> {
+        match t {
+            ty::UintTy::Usize => self.type_isize(),
+            ty::UintTy::U8 => self.type_i8(),
+            ty::UintTy::U16 => self.type_i16(),
+            ty::UintTy::U32 => self.type_i32(),
+            ty::UintTy::U64 => self.type_i64(),
+            ty::UintTy::U128 => self.type_i128(),
+        }
+    }
 }
 
 pub fn uncached_gcc_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, layout: TyAndLayout<'tcx>, defer: &mut Option<(Struct<'gcc>, TyAndLayout<'tcx>)>) -> Type<'gcc> {
diff --git a/compiler/rustc_codegen_gcc/test.sh b/compiler/rustc_codegen_gcc/test.sh
index 1beeee1..8b390f9 100755
--- a/compiler/rustc_codegen_gcc/test.sh
+++ b/compiler/rustc_codegen_gcc/test.sh
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
 
 # TODO(antoyo): rewrite to cargo-make (or just) or something like that to only rebuild the sysroot when needed?
 
@@ -14,25 +14,87 @@
 export LD_LIBRARY_PATH="$GCC_PATH"
 export LIBRARY_PATH="$GCC_PATH"
 
-features=
+flags=
+gcc_master_branch=1
+channel="debug"
+func=all
+build_only=0
 
-if [[ "$1" == "--features" ]]; then
-    shift
-    features="--features $1"
-    shift
-fi
+while [[ $# -gt 0 ]]; do
+    case $1 in
+        --release)
+            codegen_channel=release
+            shift
+            ;;
+        --release-sysroot)
+            sysroot_channel=release
+            shift
+            ;;
+        --no-default-features)
+            gcc_master_branch=0
+            flags="$flags --no-default-features"
+            shift
+            ;;
+        --features)
+            shift
+            flags="$flags --features $1"
+            shift
+            ;;
+        --release)
+            channel="release"
+            shift
+            ;;
+        "--test-rustc")
+            func=test_rustc
+            shift
+            ;;
 
-if [[ "$1" == "--release" ]]; then
+        "--test-libcore")
+            func=test_libcore
+            shift
+            ;;
+
+        "--clean-ui-tests")
+            func=clean_ui_tests
+            shift
+            ;;
+
+        "--std-tests")
+            func=std_tests
+            shift
+            ;;
+
+        "--extended-tests")
+            func=extended_sysroot_tests
+            shift
+            ;;
+
+        "--build-sysroot")
+            func=build_sysroot
+            shift
+            ;;
+        "--build")
+            build_only=1
+            shift
+            ;;
+        *)
+            echo "Unknown option $1"
+            exit 1
+            ;;
+    esac
+done
+
+if [[ $channel == "release" ]]; then
     export CHANNEL='release'
-    CARGO_INCREMENTAL=1 cargo rustc --release $features
+    CARGO_INCREMENTAL=1 cargo rustc --release $flags
     shift
 else
     echo $LD_LIBRARY_PATH
     export CHANNEL='debug'
-    cargo rustc $features
+    cargo rustc $flags
 fi
 
-if [[ "$1" == "--build" ]]; then
+if (( $build_only == 1 )); then
     exit
 fi
 
@@ -78,7 +140,11 @@
     $RUN_WRAPPER ./target/out/dst_field_align || (echo $?; false)
 
     echo "[AOT] std_example"
-    $RUSTC example/std_example.rs --crate-type bin --target $TARGET_TRIPLE
+    std_flags="--cfg feature=\"master\""
+    if (( $gcc_master_branch == 0 )); then
+        std_flags=""
+    fi
+    $RUSTC example/std_example.rs --crate-type bin --target $TARGET_TRIPLE $std_flags
     $RUN_WRAPPER ./target/out/std_example --target $TARGET_TRIPLE
 
     echo "[AOT] subslice-patterns-const-eval"
@@ -97,25 +163,6 @@
 #echo "[BUILD] sysroot in release mode"
 #./build_sysroot/build_sysroot.sh --release
 
-# TODO(antoyo): uncomment when it works.
-#pushd simple-raytracer
-#if [[ "$HOST_TRIPLE" = "$TARGET_TRIPLE" ]]; then
-    #echo "[BENCH COMPILE] ebobby/simple-raytracer"
-    #hyperfine --runs ${RUN_RUNS:-10} --warmup 1 --prepare "rm -r target/*/debug || true" \
-    #"RUSTFLAGS='' cargo build --target $TARGET_TRIPLE" \
-    #"../cargo.sh build"
-
-    #echo "[BENCH RUN] ebobby/simple-raytracer"
-    #cp ./target/*/debug/main ./raytracer_cg_gccjit
-    #hyperfine --runs ${RUN_RUNS:-10} ./raytracer_cg_llvm ./raytracer_cg_gccjit
-#else
-    #echo "[BENCH COMPILE] ebobby/simple-raytracer (skipped)"
-    #echo "[COMPILE] ebobby/simple-raytracer"
-    #../cargo.sh build
-    #echo "[BENCH RUN] ebobby/simple-raytracer (skipped)"
-#fi
-#popd
-
 function test_libcore() {
     pushd build_sysroot/sysroot_src/library/core/tests
     echo "[TEST] libcore"
@@ -124,19 +171,6 @@
     popd
 }
 
-# TODO(antoyo): uncomment when it works.
-#pushd regex
-#echo "[TEST] rust-lang/regex example shootout-regex-dna"
-#../cargo.sh clean
-## Make sure `[codegen mono items] start` doesn't poison the diff
-#../cargo.sh build --example shootout-regex-dna
-#cat examples/regexdna-input.txt | ../cargo.sh run --example shootout-regex-dna | grep -v "Spawned thread" > res.txt
-#diff -u res.txt examples/regexdna-output.txt
-
-#echo "[TEST] rust-lang/regex tests"
-#../cargo.sh test --tests -- --exclude-should-panic --test-threads 1 -Zunstable-options
-#popd
-
 #echo
 #echo "[BENCH COMPILE] mod_bench"
 
@@ -153,6 +187,44 @@
 #echo "[BENCH RUN] mod_bench"
 #hyperfine --runs ${RUN_RUNS:-10} ./target/out/mod_bench{,_inline} ./target/out/mod_bench_llvm_*
 
+function extended_sysroot_tests() {
+    if (( $gcc_master_branch == 0 )); then
+        return
+    fi
+
+    pushd rand
+    cargo clean
+    echo "[TEST] rust-random/rand"
+    ../cargo.sh test --workspace
+    popd
+
+    #pushd simple-raytracer
+    #echo "[BENCH COMPILE] ebobby/simple-raytracer"
+    #hyperfine --runs "${RUN_RUNS:-10}" --warmup 1 --prepare "cargo clean" \
+    #"RUSTC=rustc RUSTFLAGS='' cargo build" \
+    #"../cargo.sh build"
+
+    #echo "[BENCH RUN] ebobby/simple-raytracer"
+    #cp ./target/debug/main ./raytracer_cg_gcc
+    #hyperfine --runs "${RUN_RUNS:-10}" ./raytracer_cg_llvm ./raytracer_cg_gcc
+    #popd
+
+    pushd regex
+    echo "[TEST] rust-lang/regex example shootout-regex-dna"
+    cargo clean
+    export CG_RUSTFLAGS="--cap-lints warn" # newer aho_corasick versions throw a deprecation warning
+    # Make sure `[codegen mono items] start` doesn't poison the diff
+    ../cargo.sh build --example shootout-regex-dna
+    cat examples/regexdna-input.txt \
+        | ../cargo.sh run --example shootout-regex-dna \
+        | grep -v "Spawned thread" > res.txt
+    diff -u res.txt examples/regexdna-output.txt
+
+    echo "[TEST] rust-lang/regex tests"
+    ../cargo.sh test --tests -- --exclude-should-panic --test-threads 1 -Zunstable-options -q
+    popd
+}
+
 function test_rustc() {
     echo
     echo "[TEST] rust-lang/rust"
@@ -165,23 +237,7 @@
     git checkout $(rustc -V | cut -d' ' -f3 | tr -d '(')
     export RUSTFLAGS=
 
-    git apply - <<EOF
-diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs
-index 887d27fd6dca4..2c2239f2b83d1 100644
---- a/src/tools/compiletest/src/header.rs
-+++ b/src/tools/compiletest/src/header.rs
-@@ -806,8 +806,8 @@ pub fn make_test_description<R: Read>(
-     cfg: Option<&str>,
- ) -> test::TestDesc {
-     let mut ignore = false;
-     #[cfg(not(bootstrap))]
--    let ignore_message: Option<String> = None;
-+    let ignore_message: Option<&str> = None;
-     let mut should_fail = false;
-
-     let rustc_has_profiler_support = env::var_os("RUSTC_PROFILER_SUPPORT").is_some();
-
-EOF
+    git apply ../rustc_patches/compile_test.patch || true
 
     rm config.toml || true
 
@@ -205,7 +261,7 @@
 
     git checkout -- src/test/ui/issues/auxiliary/issue-3136-a.rs # contains //~ERROR, but shouldn't be removed
 
-    rm -r src/test/ui/{abi*,extern/,panic-runtime/,panics/,unsized-locals/,proc-macro/,threads-sendsync/,thinlto/,simd*,borrowck/,test*,*lto*.rs} || true
+    rm -r src/test/ui/{abi*,extern/,panic-runtime/,panics/,unsized-locals/,proc-macro/,threads-sendsync/,thinlto/,borrowck/,test*,*lto*.rs} || true
     for test in $(rg --files-with-matches "catch_unwind|should_panic|thread|lto" src/test/ui); do
       rm $test
     done
@@ -222,33 +278,14 @@
     find rust/build/x86_64-unknown-linux-gnu/test/ui/ -name stamp -exec rm -rf {} \;
 }
 
-case $1 in
-    "--test-rustc")
-        test_rustc
-        ;;
+function all() {
+    clean
+    mini_tests
+    build_sysroot
+    std_tests
+    test_libcore
+    extended_sysroot_tests
+    test_rustc
+}
 
-    "--test-libcore")
-        test_libcore
-        ;;
-
-    "--clean-ui-tests")
-        clean_ui_tests
-        ;;
-
-    "--std-tests")
-        std_tests
-        ;;
-
-    "--build-sysroot")
-        build_sysroot
-        ;;
-
-    *)
-        clean
-        mini_tests
-        build_sysroot
-        std_tests
-        test_libcore
-        test_rustc
-        ;;
-esac
+$func
diff --git a/compiler/rustc_codegen_gcc/tests/lib.rs b/compiler/rustc_codegen_gcc/tests/lang_tests_common.rs
similarity index 76%
rename from compiler/rustc_codegen_gcc/tests/lib.rs
rename to compiler/rustc_codegen_gcc/tests/lang_tests_common.rs
index 8ee35b3..8e37817 100644
--- a/compiler/rustc_codegen_gcc/tests/lib.rs
+++ b/compiler/rustc_codegen_gcc/tests/lang_tests_common.rs
@@ -1,3 +1,4 @@
+//! The common code for `tests/lang_tests_*.rs`
 use std::{
     env::{self, current_dir},
     path::PathBuf,
@@ -7,7 +8,15 @@
 use lang_tester::LangTester;
 use tempfile::TempDir;
 
-fn main() {
+/// Controls the compile options (e.g., optimization level) used to compile
+/// test code.
+#[allow(dead_code)] // Each test crate picks one variant
+pub enum Profile {
+    Debug,
+    Release,
+}
+
+pub fn main_inner(profile: Profile) {
     let tempdir = TempDir::new().expect("temp dir");
     let current_dir = current_dir().expect("current dir");
     let current_dir = current_dir.to_str().expect("current dir").to_string();
@@ -42,6 +51,15 @@
                 "-o", exe.to_str().expect("to_str"),
                 path.to_str().expect("to_str"),
             ]);
+            match profile {
+                Profile::Debug => {}
+                Profile::Release => {
+                    compiler.args(&[
+                        "-C", "opt-level=3",
+                        "-C", "lto=no",
+                    ]);
+                }
+            }
             // Test command 2: run `tempdir/x`.
             let runtime = Command::new(exe);
             vec![("Compiler", compiler), ("Run-time", runtime)]
diff --git a/compiler/rustc_codegen_gcc/tests/lang_tests_debug.rs b/compiler/rustc_codegen_gcc/tests/lang_tests_debug.rs
new file mode 100644
index 0000000..96bd748
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/tests/lang_tests_debug.rs
@@ -0,0 +1,5 @@
+mod lang_tests_common;
+
+fn main() {
+    lang_tests_common::main_inner(lang_tests_common::Profile::Debug);
+}
diff --git a/compiler/rustc_codegen_gcc/tests/lang_tests_release.rs b/compiler/rustc_codegen_gcc/tests/lang_tests_release.rs
new file mode 100644
index 0000000..35d5d60
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/tests/lang_tests_release.rs
@@ -0,0 +1,5 @@
+mod lang_tests_common;
+
+fn main() {
+    lang_tests_common::main_inner(lang_tests_common::Profile::Release);
+}
diff --git a/compiler/rustc_codegen_gcc/tests/run/int.rs b/compiler/rustc_codegen_gcc/tests/run/int.rs
index 4937601..2b90e4a 100644
--- a/compiler/rustc_codegen_gcc/tests/run/int.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/int.rs
@@ -3,32 +3,13 @@
 // Run-time:
 //   status: 0
 
-#![feature(arbitrary_self_types, auto_traits, core_intrinsics, lang_items, start, intrinsics)]
+#![feature(bench_black_box, const_black_box, core_intrinsics, start)]
 
 #![no_std]
 
-mod intrinsics {
-    extern "rust-intrinsic" {
-        pub fn abort() -> !;
-    }
-}
-
-/*
- * Core
- */
-
-mod libc {
-    #[link(name = "c")]
-    extern "C" {
-        pub fn puts(s: *const u8) -> i32;
-    }
-}
-
 #[panic_handler]
 fn panic_handler(_: &core::panic::PanicInfo) -> ! {
-    unsafe {
-        core::intrinsics::abort();
-    }
+    core::intrinsics::abort();
 }
 
 /*
@@ -36,118 +17,324 @@
  */
 
 #[start]
-fn main(argc: isize, _argv: *const *const u8) -> isize {
-    let var = 134217856_u128;
-    let var2 = 10475372733397991552_u128;
-    let var3 = 193236519889708027473620326106273939584_u128;
-    let var4 = 123236519889708027473620326106273939584_u128;
-    let var5 = 153236519889708027473620326106273939584_u128;
-    let var6 = 18446744073709551616_i128;
-    let var7 = 170141183460469231731687303715884105728_u128;
+fn main(_argc: isize, _argv: *const *const u8) -> isize {
+    use core::hint::black_box;
 
-    // Shifts.
-    assert_eq!(var << (argc as u128 - 1), var);
-    assert_eq!(var << argc as u128, 268435712);
-    assert_eq!(var << (argc + 32) as u128, 1152922604118474752);
-    assert_eq!(var << (argc + 48) as u128, 75557935783508361347072);
-    assert_eq!(var << (argc + 60) as u128, 309485304969250248077606912);
-    assert_eq!(var << (argc + 62) as u128, 1237941219877000992310427648);
-    assert_eq!(var << (argc + 63) as u128, 2475882439754001984620855296);
-    assert_eq!(var << (argc + 80) as u128, 324518863143436548128224745357312);
+    macro_rules! check {
+        ($ty:ty, $expr:expr) => {
+            {
+                const EXPECTED: $ty = $expr;
+                assert_eq!($expr, EXPECTED);
+            }
+        };
+    }
 
-    assert_eq!(var2 << argc as u128, 20950745466795983104);
-    assert_eq!(var2 << (argc as u128 - 1), var2);
-    assert_eq!(var2 << (argc + 32) as u128, 89982766606709001335848566784);
-    assert_eq!(var2 << (argc + 48) as u128, 5897110592337281111546171672756224);
-    assert_eq!(var2 << (argc + 60) as u128, 24154564986213503432893119171609493504);
-    assert_eq!(var2 << (argc + 62) as u128, 96618259944854013731572476686437974016);
-    assert_eq!(var2 << (argc + 63) as u128, 193236519889708027463144953372875948032);
+    check!(u32, (2220326408_u32 + black_box(1)) >> (32 - 6));
 
-    assert_eq!(var3 << argc as u128, 46190672858477591483866044780779667712);
-    assert_eq!(var3 << (argc as u128 - 1), var3);
-    assert_eq!(var3 << (argc + 32) as u128, 21267668304951024224840338247585366016);
-    assert_eq!(var3 << (argc + 48) as u128, 1335125106377253154015353231953100800);
-    assert_eq!(var3 << (argc + 60) as u128, 24154564986213503432893119171609493504);
-    assert_eq!(var3 << (argc + 62) as u128, 96618259944854013731572476686437974016);
-    assert_eq!(var3 << (argc + 63) as u128, 193236519889708027463144953372875948032);
+    /// Generate `check!` tests for integer types at least as wide as 128 bits.
+    macro_rules! check_ops128 {
+        () => {
+            check_ops64!();
 
-    assert_eq!((2220326408_u32 + argc as u32) >> (32 - 6), 33);
+            // Shifts.
+            check!(T, VAL1 << black_box(64));
+            check!(T, VAL1 << black_box(81));
+            check!(T, VAL3 << black_box(63));
+            check!(T, VAL3 << black_box(64));
 
-    assert_eq!(var >> (argc as u128 - 1), var);
-    assert_eq!(var >> argc as u128, 67108928);
-    assert_eq!(var >> (argc + 32) as u128, 0);
-    assert_eq!(var >> (argc + 48) as u128, 0);
-    assert_eq!(var >> (argc + 60) as u128, 0);
-    assert_eq!(var >> (argc + 62) as u128, 0);
-    assert_eq!(var >> (argc + 63) as u128, 0);
+            check!(T, VAL1 >> black_box(64));
+            check!(T, VAL2 >> black_box(64));
+            check!(T, VAL3 >> black_box(64));
+            check!(T, VAL3 >> black_box(81));
+        };
+    }
 
-    assert_eq!(var2 >> argc as u128, 5237686366698995776);
-    assert_eq!(var2 >> (argc as u128 - 1), var2);
-    assert_eq!(var2 >> (argc + 32) as u128, 1219493888);
-    assert_eq!(var2 >> (argc + 48) as u128, 18608);
-    assert_eq!(var2 >> (argc + 60) as u128, 4);
-    assert_eq!(var2 >> (argc + 62) as u128, 1);
-    assert_eq!(var2 >> (argc + 63) as u128, 0);
+    /// Generate `check!` tests for integer types at least as wide as 64 bits.
+    macro_rules! check_ops64 {
+        () => {
+            check_ops32!();
 
-    assert_eq!(var3 >> (argc as u128 - 1), var3);
-    assert_eq!(var3 >> argc as u128, 96618259944854013736810163053136969792);
-    assert_eq!(var3 >> (argc + 32) as u128, 22495691651677250335181635584);
-    assert_eq!(var3 >> (argc + 48) as u128, 343257013727985387194544);
-    assert_eq!(var3 >> (argc + 60) as u128, 83802981867183932420);
-    assert_eq!(var3 >> (argc + 62) as u128, 20950745466795983105);
-    assert_eq!(var3 >> (argc + 63) as u128, 10475372733397991552);
-    assert_eq!(var3 >> (argc + 80) as u128, 79920751444992);
+            // Shifts.
+            check!(T, VAL2 << black_box(33));
+            check!(T, VAL2 << black_box(49));
+            check!(T, VAL2 << black_box(61));
+            check!(T, VAL2 << black_box(63));
 
-    assert_eq!(var6 >> argc as u128, 9223372036854775808);
-    assert_eq!((var6 - 1) >> argc as u128, 9223372036854775807);
-    assert_eq!(var7 >> argc as u128, 85070591730234615865843651857942052864);
+            check!(T, VAL3 << black_box(33));
+            check!(T, VAL3 << black_box(49));
+            check!(T, VAL3 << black_box(61));
 
-    // Casts
-    assert_eq!((var >> (argc + 32) as u128) as u64, 0);
-    assert_eq!((var >> argc as u128) as u64, 67108928);
+            check!(T, VAL1 >> black_box(33));
+            check!(T, VAL1 >> black_box(49));
+            check!(T, VAL1 >> black_box(61));
+            check!(T, VAL1 >> black_box(63));
 
-    // Addition.
-    assert_eq!(var + argc as u128, 134217857);
+            check!(T, VAL2 >> black_box(33));
+            check!(T, VAL2 >> black_box(49));
+            check!(T, VAL2 >> black_box(61));
+            check!(T, VAL2 >> black_box(63));
 
-    assert_eq!(var2 + argc as u128, 10475372733397991553);
-    assert_eq!(var2 + (var2 + argc as u128) as u128, 20950745466795983105);
+            check!(T, VAL3 >> black_box(33));
+            check!(T, VAL3 >> black_box(49));
+            check!(T, VAL3 >> black_box(61));
+            check!(T, VAL3 >> black_box(63));
+        };
+    }
 
-    assert_eq!(var3 + argc as u128, 193236519889708027473620326106273939585);
+    /// Generate `check!` tests for integer types at least as wide as 32 bits.
+    macro_rules! check_ops32 {
+        () => {
+            // Shifts.
+            check!(T, VAL2 << black_box(1));
+            check!(T, VAL2 << black_box(0));
 
-    // Subtraction
-    assert_eq!(var - argc as u128, 134217855);
+            check!(T, VAL3 << black_box(1));
+            check!(T, VAL3 << black_box(0));
 
-    assert_eq!(var2 - argc as u128, 10475372733397991551);
+            check!(T, VAL1.wrapping_shl(black_box(0)));
+            check!(T, VAL1.wrapping_shl(black_box(1)));
+            check!(T, VAL1.wrapping_shl(black_box(33)));
+            check!(T, VAL1.wrapping_shl(black_box(49)));
+            check!(T, VAL1.wrapping_shl(black_box(61)));
+            check!(T, VAL1.wrapping_shl(black_box(63)));
+            check!(T, VAL1.wrapping_shl(black_box(64)));
+            check!(T, VAL1.wrapping_shl(black_box(81)));
 
-    assert_eq!(var3 - argc as u128, 193236519889708027473620326106273939583);
+            check!(Option<T>, VAL1.checked_shl(black_box(0)));
+            check!(Option<T>, VAL1.checked_shl(black_box(1)));
+            check!(Option<T>, VAL1.checked_shl(black_box(33)));
+            check!(Option<T>, VAL1.checked_shl(black_box(49)));
+            check!(Option<T>, VAL1.checked_shl(black_box(61)));
+            check!(Option<T>, VAL1.checked_shl(black_box(63)));
+            check!(Option<T>, VAL1.checked_shl(black_box(64)));
+            check!(Option<T>, VAL1.checked_shl(black_box(81)));
 
-    // Multiplication
-    assert_eq!(var * (argc + 1) as u128, 268435712);
-    assert_eq!(var * (argc as u128 + var2), 1405982069077538020949770368);
+            check!(T, VAL1 >> black_box(0));
+            check!(T, VAL1 >> black_box(1));
 
-    assert_eq!(var2 * (argc + 1) as u128, 20950745466795983104);
-    assert_eq!(var2 * (argc as u128 + var2), 109733433903618109003204073240861360256);
+            check!(T, VAL2 >> black_box(1));
+            check!(T, VAL2 >> black_box(0));
 
-    assert_eq!(var3 * argc as u128, 193236519889708027473620326106273939584);
+            check!(T, VAL3 >> black_box(0));
+            check!(T, VAL3 >> black_box(1));
 
-    assert_eq!(var4 * (argc + 1) as u128, 246473039779416054947240652212547879168);
+            check!(T, VAL1.wrapping_shr(black_box(0)));
+            check!(T, VAL1.wrapping_shr(black_box(1)));
+            check!(T, VAL1.wrapping_shr(black_box(33)));
+            check!(T, VAL1.wrapping_shr(black_box(49)));
+            check!(T, VAL1.wrapping_shr(black_box(61)));
+            check!(T, VAL1.wrapping_shr(black_box(63)));
+            check!(T, VAL1.wrapping_shr(black_box(64)));
+            check!(T, VAL1.wrapping_shr(black_box(81)));
 
-    assert_eq!(var5 * (argc + 1) as u128, 306473039779416054947240652212547879168);
+            check!(Option<T>, VAL1.checked_shr(black_box(0)));
+            check!(Option<T>, VAL1.checked_shr(black_box(1)));
+            check!(Option<T>, VAL1.checked_shr(black_box(33)));
+            check!(Option<T>, VAL1.checked_shr(black_box(49)));
+            check!(Option<T>, VAL1.checked_shr(black_box(61)));
+            check!(Option<T>, VAL1.checked_shr(black_box(63)));
+            check!(Option<T>, VAL1.checked_shr(black_box(64)));
+            check!(Option<T>, VAL1.checked_shr(black_box(81)));
 
-    // Division.
-    assert_eq!(var / (argc + 1) as u128, 67108928);
-    assert_eq!(var / (argc + 2) as u128, 44739285);
+            // Casts
+            check!(u64, (VAL1 >> black_box(1)) as u64);
 
-    assert_eq!(var2 / (argc + 1) as u128, 5237686366698995776);
-    assert_eq!(var2 / (argc + 2) as u128, 3491790911132663850);
+            // Addition.
+            check!(T, VAL1 + black_box(1));
+            check!(T, VAL2 + black_box(1));
+            check!(T, VAL2 + (VAL2 + black_box(1)));
+            check!(T, VAL3 + black_box(1));
 
-    assert_eq!(var3 / (argc + 1) as u128, 96618259944854013736810163053136969792);
-    assert_eq!(var3 / (argc + 2) as u128, 64412173296569342491206775368757979861);
-    assert_eq!(var3 / (argc as u128 + var4), 1);
-    assert_eq!(var3 / (argc as u128 + var2), 18446744073709551615);
+            check!(Option<T>, VAL1.checked_add(black_box(1)));
+            check!(Option<T>, VAL2.checked_add(black_box(1)));
+            check!(Option<T>, VAL2.checked_add(VAL2 + black_box(1)));
+            check!(Option<T>, VAL3.checked_add(T::MAX));
+            check!(Option<T>, VAL3.checked_add(T::MIN));
 
-    assert_eq!(var4 / (argc + 1) as u128, 61618259944854013736810163053136969792);
-    assert_eq!(var4 / (argc + 2) as u128, 41078839963236009157873442035424646528);
+            check!(T, VAL1.wrapping_add(black_box(1)));
+            check!(T, VAL2.wrapping_add(black_box(1)));
+            check!(T, VAL2.wrapping_add(VAL2 + black_box(1)));
+            check!(T, VAL3.wrapping_add(T::MAX));
+            check!(T, VAL3.wrapping_add(T::MIN));
+
+            check!((T, bool), VAL1.overflowing_add(black_box(1)));
+            check!((T, bool), VAL2.overflowing_add(black_box(1)));
+            check!((T, bool), VAL2.overflowing_add(VAL2 + black_box(1)));
+            check!((T, bool), VAL3.overflowing_add(T::MAX));
+            check!((T, bool), VAL3.overflowing_add(T::MIN));
+
+            check!(T, VAL1.saturating_add(black_box(1)));
+            check!(T, VAL2.saturating_add(black_box(1)));
+            check!(T, VAL2.saturating_add(VAL2 + black_box(1)));
+            check!(T, VAL3.saturating_add(T::MAX));
+            check!(T, VAL3.saturating_add(T::MIN));
+
+            // Subtraction
+            check!(T, VAL1 - black_box(1));
+            check!(T, VAL2 - black_box(1));
+            check!(T, VAL3 - black_box(1));
+
+            check!(Option<T>, VAL1.checked_sub(black_box(1)));
+            check!(Option<T>, VAL2.checked_sub(black_box(1)));
+            check!(Option<T>, VAL2.checked_sub(VAL2 + black_box(1)));
+            check!(Option<T>, VAL3.checked_sub(T::MAX));
+            check!(Option<T>, VAL3.checked_sub(T::MIN));
+
+            check!(T, VAL1.wrapping_sub(black_box(1)));
+            check!(T, VAL2.wrapping_sub(black_box(1)));
+            check!(T, VAL2.wrapping_sub(VAL2 + black_box(1)));
+            check!(T, VAL3.wrapping_sub(T::MAX));
+            check!(T, VAL3.wrapping_sub(T::MIN));
+
+            check!((T, bool), VAL1.overflowing_sub(black_box(1)));
+            check!((T, bool), VAL2.overflowing_sub(black_box(1)));
+            check!((T, bool), VAL2.overflowing_sub(VAL2 + black_box(1)));
+            check!((T, bool), VAL3.overflowing_sub(T::MAX));
+            check!((T, bool), VAL3.overflowing_sub(T::MIN));
+
+            check!(T, VAL1.saturating_sub(black_box(1)));
+            check!(T, VAL2.saturating_sub(black_box(1)));
+            check!(T, VAL2.saturating_sub(VAL2 + black_box(1)));
+            check!(T, VAL3.saturating_sub(T::MAX));
+            check!(T, VAL3.saturating_sub(T::MIN));
+
+            // Multiplication
+            check!(T, VAL1 * black_box(2));
+            check!(T, VAL1 * (black_box(1) + VAL2));
+            check!(T, VAL2 * black_box(2));
+            check!(T, VAL2 * (black_box(1) + VAL2));
+            check!(T, VAL3 * black_box(1));
+            check!(T, VAL4 * black_box(2));
+            check!(T, VAL5 * black_box(2));
+
+            check!(Option<T>, VAL1.checked_mul(black_box(2)));
+            check!(Option<T>, VAL1.checked_mul(black_box(1) + VAL2));
+            check!(Option<T>, VAL3.checked_mul(VAL3));
+            check!(Option<T>, VAL4.checked_mul(black_box(2)));
+            check!(Option<T>, VAL5.checked_mul(black_box(2)));
+
+            check!(T, VAL1.wrapping_mul(black_box(2)));
+            check!(T, VAL1.wrapping_mul((black_box(1) + VAL2)));
+            check!(T, VAL3.wrapping_mul(VAL3));
+            check!(T, VAL4.wrapping_mul(black_box(2)));
+            check!(T, VAL5.wrapping_mul(black_box(2)));
+
+            check!((T, bool), VAL1.overflowing_mul(black_box(2)));
+            check!((T, bool), VAL1.overflowing_mul(black_box(1) + VAL2));
+            check!((T, bool), VAL3.overflowing_mul(VAL3));
+            check!((T, bool), VAL4.overflowing_mul(black_box(2)));
+            check!((T, bool), VAL5.overflowing_mul(black_box(2)));
+
+            check!(T, VAL1.saturating_mul(black_box(2)));
+            check!(T, VAL1.saturating_mul(black_box(1) + VAL2));
+            check!(T, VAL3.saturating_mul(VAL3));
+            check!(T, VAL4.saturating_mul(black_box(2)));
+            check!(T, VAL5.saturating_mul(black_box(2)));
+
+            // Division.
+            check!(T, VAL1 / black_box(2));
+            check!(T, VAL1 / black_box(3));
+
+            check!(T, VAL2 / black_box(2));
+            check!(T, VAL2 / black_box(3));
+
+            check!(T, VAL3 / black_box(2));
+            check!(T, VAL3 / black_box(3));
+            check!(T, VAL3 / (black_box(1) + VAL4));
+            check!(T, VAL3 / (black_box(1) + VAL2));
+
+            check!(T, VAL4 / black_box(2));
+            check!(T, VAL4 / black_box(3));
+
+            check!(Option<T>, VAL1.checked_div(black_box(2)));
+            check!(Option<T>, VAL1.checked_div(black_box(1) + VAL2));
+            check!(Option<T>, VAL3.checked_div(VAL3));
+            check!(Option<T>, VAL4.checked_div(black_box(2)));
+            check!(Option<T>, VAL5.checked_div(black_box(2)));
+            check!(Option<T>, (T::MIN).checked_div(black_box(0 as T).wrapping_sub(1)));
+            check!(Option<T>, VAL5.checked_div(black_box(0))); // var5 / 0
+
+            check!(T, VAL1.wrapping_div(black_box(2)));
+            check!(T, VAL1.wrapping_div(black_box(1) + VAL2));
+            check!(T, VAL3.wrapping_div(VAL3));
+            check!(T, VAL4.wrapping_div(black_box(2)));
+            check!(T, VAL5.wrapping_div(black_box(2)));
+            check!(T, (T::MIN).wrapping_div(black_box(0 as T).wrapping_sub(1)));
+
+            check!((T, bool), VAL1.overflowing_div(black_box(2)));
+            check!((T, bool), VAL1.overflowing_div(black_box(1) + VAL2));
+            check!((T, bool), VAL3.overflowing_div(VAL3));
+            check!((T, bool), VAL4.overflowing_div(black_box(2)));
+            check!((T, bool), VAL5.overflowing_div(black_box(2)));
+            check!((T, bool), (T::MIN).overflowing_div(black_box(0 as T).wrapping_sub(1)));
+
+            check!(T, VAL1.saturating_div(black_box(2)));
+            check!(T, VAL1.saturating_div((black_box(1) + VAL2)));
+            check!(T, VAL3.saturating_div(VAL3));
+            check!(T, VAL4.saturating_div(black_box(2)));
+            check!(T, VAL5.saturating_div(black_box(2)));
+            check!(T, (T::MIN).saturating_div((0 as T).wrapping_sub(black_box(1))));
+        };
+    }
+
+    {
+        type T = u32;
+        const VAL1: T = 14162_u32;
+        const VAL2: T = 14556_u32;
+        const VAL3: T = 323656954_u32;
+        const VAL4: T = 2023651954_u32;
+        const VAL5: T = 1323651954_u32;
+        check_ops32!();
+    }
+
+    {
+        type T = i32;
+        const VAL1: T = 13456_i32;
+        const VAL2: T = 10475_i32;
+        const VAL3: T = 923653954_i32;
+        const VAL4: T = 993198738_i32;
+        const VAL5: T = 1023653954_i32;
+        check_ops32!();
+    }
+
+    {
+        type T = u64;
+        const VAL1: T = 134217856_u64;
+        const VAL2: T = 104753732_u64;
+        const VAL3: T = 12323651988970863954_u64;
+        const VAL4: T = 7323651988970863954_u64;
+        const VAL5: T = 8323651988970863954_u64;
+        check_ops64!();
+    }
+
+    {
+        type T = i64;
+        const VAL1: T = 134217856_i64;
+        const VAL2: T = 104753732_i64;
+        const VAL3: T = 6323651988970863954_i64;
+        const VAL4: T = 2323651988970863954_i64;
+        const VAL5: T = 3323651988970863954_i64;
+        check_ops64!();
+    }
+
+    {
+        type T = u128;
+        const VAL1: T = 134217856_u128;
+        const VAL2: T = 10475372733397991552_u128;
+        const VAL3: T = 193236519889708027473620326106273939584_u128;
+        const VAL4: T = 123236519889708027473620326106273939584_u128;
+        const VAL5: T = 153236519889708027473620326106273939584_u128;
+        check_ops128!();
+    }
+    {
+        type T = i128;
+        const VAL1: T = 134217856_i128;
+        const VAL2: T = 10475372733397991552_i128;
+        const VAL3: T = 83236519889708027473620326106273939584_i128;
+        const VAL4: T = 63236519889708027473620326106273939584_i128;
+        const VAL5: T = 73236519889708027473620326106273939584_i128;
+        check_ops128!();
+    }
 
     0
 }
diff --git a/compiler/rustc_codegen_gcc/tests/run/int_overflow.rs b/compiler/rustc_codegen_gcc/tests/run/int_overflow.rs
index 6477b83..ea2c5ad 100644
--- a/compiler/rustc_codegen_gcc/tests/run/int_overflow.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/int_overflow.rs
@@ -1,7 +1,7 @@
 // Compiler:
 //
 // Run-time:
-//   stdout: Panicking
+//   stdout: Success
 //   status: signal
 
 #![allow(unused_attributes)]
@@ -64,7 +64,9 @@
 #[no_mangle]
 pub fn panic(_msg: &str) -> ! {
     unsafe {
-        libc::puts("Panicking\0" as *const str as *const u8);
+        // Panicking is expected iff overflow checking is enabled.
+        #[cfg(debug_assertions)]
+        libc::puts("Success\0" as *const str as *const u8);
         libc::fflush(libc::stdout);
         intrinsics::abort();
     }
@@ -124,6 +126,15 @@
 #[start]
 fn main(mut argc: isize, _argv: *const *const u8) -> isize {
     let int = 9223372036854775807isize;
-    let int = int + argc;
+    let int = int + argc;  // overflow
+
+    // If overflow checking is disabled, we should reach here.
+    #[cfg(not(debug_assertions))]
+    unsafe {
+        libc::puts("Success\0" as *const str as *const u8);
+        libc::fflush(libc::stdout);
+        intrinsics::abort();
+    }
+
     int
 }
diff --git a/compiler/rustc_codegen_gcc/tools/generate_intrinsics.py b/compiler/rustc_codegen_gcc/tools/generate_intrinsics.py
new file mode 100644
index 0000000..849c6e9
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/tools/generate_intrinsics.py
@@ -0,0 +1,238 @@
+import json
+import os
+import re
+import sys
+import subprocess
+from os import walk
+
+
+def run_command(command, cwd=None):
+    p = subprocess.Popen(command, cwd=cwd)
+    if p.wait() != 0:
+        print("command `{}` failed...".format(" ".join(command)))
+        sys.exit(1)
+
+
+def clone_repository(repo_name, path, repo_url, sub_path=None):
+    if os.path.exists(path):
+        while True:
+            choice = input("There is already a `{}` folder, do you want to update it? [y/N]".format(path))
+            if choice == "" or choice.lower() == "n":
+                print("Skipping repository update.")
+                return
+            elif choice.lower() == "y":
+                print("Updating repository...")
+                run_command(["git", "pull", "origin"], cwd=path)
+                return
+            else:
+                print("Didn't understand answer...")
+    print("Cloning {} repository...".format(repo_name))
+    if sub_path is None:
+        run_command(["git", "clone", repo_url, "--depth", "1", path])
+    else:
+        run_command(["git", "clone", repo_url, "--filter=tree:0", "--no-checkout", path])
+        run_command(["git", "sparse-checkout", "init"], cwd=path)
+        run_command(["git", "sparse-checkout", "set", "add", sub_path], cwd=path)
+        run_command(["git", "checkout"], cwd=path)
+
+
+def append_intrinsic(array, intrinsic_name, translation):
+    array.append((intrinsic_name, translation))
+
+
+def extract_instrinsics(intrinsics, file):
+    print("Extracting intrinsics from `{}`...".format(file))
+    with open(file, "r", encoding="utf8") as f:
+        content = f.read()
+
+    lines = content.splitlines()
+    pos = 0
+    current_arch = None
+    while pos < len(lines):
+        line = lines[pos].strip()
+        if line.startswith("let TargetPrefix ="):
+            current_arch = line.split('"')[1].strip()
+            if len(current_arch) == 0:
+                current_arch = None
+        elif current_arch is None:
+            pass
+        elif line == "}":
+            current_arch = None
+        elif line.startswith("def "):
+            content = ""
+            while not content.endswith(";") and not content.endswith("}") and pos < len(lines):
+                line = lines[pos].split(" // ")[0].strip()
+                content += line
+                pos += 1
+            entries = re.findall('GCCBuiltin<"(\\w+)">', content)
+            if len(entries) > 0:
+                intrinsic = content.split("def ")[1].strip().split(":")[0].strip()
+                intrinsic = intrinsic.split("_")
+                if len(intrinsic) < 2 or intrinsic[0] != "int":
+                    continue
+                intrinsic[0] = "llvm"
+                intrinsic = ".".join(intrinsic)
+                if current_arch not in intrinsics:
+                    intrinsics[current_arch] = []
+                for entry in entries:
+                    append_intrinsic(intrinsics[current_arch], intrinsic, entry)
+            continue
+        pos += 1
+        continue
+    print("Done!")
+
+
+def extract_instrinsics_from_llvm(llvm_path, intrinsics):
+    files = []
+    intrinsics_path = os.path.join(llvm_path, "llvm/include/llvm/IR")
+    for (dirpath, dirnames, filenames) in walk(intrinsics_path):
+        files.extend([os.path.join(intrinsics_path, f) for f in filenames if f.endswith(".td")])
+
+    for file in files:
+        extract_instrinsics(intrinsics, file)
+
+
+def append_translation(json_data, p, array):
+    it = json_data["index"][p]
+    content = it["docs"].split('`')
+    if len(content) != 5:
+        return
+    append_intrinsic(array, content[1], content[3])
+
+
+def extract_instrinsics_from_llvmint(llvmint, intrinsics):
+    archs = [
+        "AMDGPU",
+        "aarch64",
+        "arm",
+        "cuda",
+        "hexagon",
+        "mips",
+        "nvvm",
+        "ppc",
+        "ptx",
+        "x86",
+        "xcore",
+    ]
+
+    json_file = os.path.join(llvmint, "target/doc/llvmint.json")
+    # We need to regenerate the documentation!
+    run_command(
+        ["cargo", "rustdoc", "--", "-Zunstable-options", "--output-format", "json"],
+        cwd=llvmint,
+    )
+    with open(json_file, "r", encoding="utf8") as f:
+        json_data = json.loads(f.read())
+    for p in json_data["paths"]:
+        it = json_data["paths"][p]
+        if it["crate_id"] != 0:
+            # This is from an external crate.
+            continue
+        if it["kind"] != "function":
+            # We're only looking for functions.
+            continue
+        # if len(it["path"]) == 2:
+        #   # This is a "general" intrinsic, not bound to a specific arch.
+        #   append_translation(json_data, p, general)
+        #   continue
+        if len(it["path"]) != 3 or it["path"][1] not in archs:
+            continue
+        arch = it["path"][1]
+        if arch not in intrinsics:
+            intrinsics[arch] = []
+        append_translation(json_data, p, intrinsics[arch])
+
+
+def fill_intrinsics(intrinsics, from_intrinsics, all_intrinsics):
+    for arch in from_intrinsics:
+        if arch not in intrinsics:
+            intrinsics[arch] = []
+        for entry in from_intrinsics[arch]:
+            if entry[0] in all_intrinsics:
+                if all_intrinsics[entry[0]] == entry[1]:
+                    # This is a "full" duplicate, both the LLVM instruction and the GCC
+                    # translation are the same.
+                    continue
+                intrinsics[arch].append((entry[0], entry[1], True))
+            else:
+                intrinsics[arch].append((entry[0], entry[1], False))
+                all_intrinsics[entry[0]] = entry[1]
+
+
+def update_intrinsics(llvm_path, llvmint, llvmint2):
+    intrinsics_llvm = {}
+    intrinsics_llvmint = {}
+    all_intrinsics = {}
+
+    extract_instrinsics_from_llvm(llvm_path, intrinsics_llvm)
+    extract_instrinsics_from_llvmint(llvmint, intrinsics_llvmint)
+    extract_instrinsics_from_llvmint(llvmint2, intrinsics_llvmint)
+
+    intrinsics = {}
+    # We give priority to translations from LLVM over the ones from llvmint.
+    fill_intrinsics(intrinsics, intrinsics_llvm, all_intrinsics)
+    fill_intrinsics(intrinsics, intrinsics_llvmint, all_intrinsics)
+
+    archs = [arch for arch in intrinsics]
+    archs.sort()
+
+    output_file = os.path.join(
+        os.path.dirname(os.path.abspath(__file__)),
+        "../src/intrinsic/archs.rs",
+    )
+    print("Updating content of `{}`...".format(output_file))
+    with open(output_file, "w", encoding="utf8") as out:
+        out.write("// File generated by `rustc_codegen_gcc/tools/generate_intrinsics.py`\n")
+        out.write("// DO NOT EDIT IT!\n")
+        out.write("match name {\n")
+        for arch in archs:
+            if len(intrinsics[arch]) == 0:
+                continue
+            intrinsics[arch].sort(key=lambda x: (x[0], x[2]))
+            out.write('    // {}\n'.format(arch))
+            for entry in intrinsics[arch]:
+                if entry[2] == True: # if it is a duplicate
+                    out.write('    // [DUPLICATE]: "{}" => "{}",\n'.format(entry[0], entry[1]))
+                else:
+                    out.write('    "{}" => "{}",\n'.format(entry[0], entry[1]))
+        out.write('    _ => unimplemented!("***** unsupported LLVM intrinsic {}", name),\n')
+        out.write("}\n")
+    print("Done!")
+
+
+def main():
+    llvm_path = os.path.join(
+        os.path.dirname(os.path.abspath(__file__)),
+        "llvm-project",
+    )
+    llvmint_path = os.path.join(
+        os.path.dirname(os.path.abspath(__file__)),
+        "llvmint",
+    )
+    llvmint2_path = os.path.join(
+        os.path.dirname(os.path.abspath(__file__)),
+        "llvmint-2",
+    )
+
+    # First, we clone the LLVM repository if it's not already here.
+    clone_repository(
+        "llvm-project",
+        llvm_path,
+        "https://github.com/llvm/llvm-project",
+        sub_path="llvm/include/llvm/IR",
+    )
+    clone_repository(
+        "llvmint",
+        llvmint_path,
+        "https://github.com/GuillaumeGomez/llvmint",
+    )
+    clone_repository(
+        "llvmint2",
+        llvmint2_path,
+        "https://github.com/antoyo/llvmint",
+    )
+    update_intrinsics(llvm_path, llvmint_path, llvmint2_path)
+
+
+if __name__ == "__main__":
+    sys.exit(main())
diff --git a/compiler/rustc_codegen_llvm/Cargo.toml b/compiler/rustc_codegen_llvm/Cargo.toml
index 67183ff..b486af1 100644
--- a/compiler/rustc_codegen_llvm/Cargo.toml
+++ b/compiler/rustc_codegen_llvm/Cargo.toml
@@ -16,9 +16,9 @@
 tracing = "0.1"
 rustc_middle = { path = "../rustc_middle" }
 rustc-demangle = "0.1.21"
-rustc_arena = { path = "../rustc_arena" }
 rustc_attr = { path = "../rustc_attr" }
 rustc_codegen_ssa = { path = "../rustc_codegen_ssa" }
+rustc_symbol_mangling = { path = "../rustc_symbol_mangling" }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_errors = { path = "../rustc_errors" }
 rustc_fs_util = { path = "../rustc_fs_util" }
diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs
index b9baa87..cc8b3a1 100644
--- a/compiler/rustc_codegen_llvm/src/abi.rs
+++ b/compiler/rustc_codegen_llvm/src/abi.rs
@@ -393,6 +393,7 @@
     fn llvm_cconv(&self) -> llvm::CallConv {
         match self.conv {
             Conv::C | Conv::Rust | Conv::CCmseNonSecureCall => llvm::CCallConv,
+            Conv::RustCold => llvm::ColdCallConv,
             Conv::AmdGpuKernel => llvm::AmdGpuKernel,
             Conv::AvrInterrupt => llvm::AvrInterrupt,
             Conv::AvrNonBlockingInterrupt => llvm::AvrNonBlockingInterrupt,
diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs
index e994001..a539469 100644
--- a/compiler/rustc_codegen_llvm/src/asm.rs
+++ b/compiler/rustc_codegen_llvm/src/asm.rs
@@ -604,7 +604,8 @@
             InlineAsmRegClass::X86(
                 X86InlineAsmRegClass::x87_reg
                 | X86InlineAsmRegClass::mmx_reg
-                | X86InlineAsmRegClass::kreg0,
+                | X86InlineAsmRegClass::kreg0
+                | X86InlineAsmRegClass::tmm_reg,
             ) => unreachable!("clobber-only"),
             InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => "r",
             InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::reg) => "r",
@@ -692,7 +693,8 @@
         InlineAsmRegClass::X86(
             X86InlineAsmRegClass::x87_reg
             | X86InlineAsmRegClass::mmx_reg
-            | X86InlineAsmRegClass::kreg0,
+            | X86InlineAsmRegClass::kreg0
+            | X86InlineAsmRegClass::tmm_reg,
         ) => {
             unreachable!("clobber-only")
         }
@@ -766,7 +768,8 @@
         InlineAsmRegClass::X86(
             X86InlineAsmRegClass::x87_reg
             | X86InlineAsmRegClass::mmx_reg
-            | X86InlineAsmRegClass::kreg0,
+            | X86InlineAsmRegClass::kreg0
+            | X86InlineAsmRegClass::tmm_reg,
         ) => {
             unreachable!("clobber-only")
         }
diff --git a/compiler/rustc_codegen_llvm/src/back/archive.rs b/compiler/rustc_codegen_llvm/src/back/archive.rs
index 8f6438e..da9d8b5 100644
--- a/compiler/rustc_codegen_llvm/src/back/archive.rs
+++ b/compiler/rustc_codegen_llvm/src/back/archive.rs
@@ -15,19 +15,12 @@
 use rustc_session::cstore::{DllCallingConvention, DllImport};
 use rustc_session::Session;
 
-struct ArchiveConfig<'a> {
-    pub sess: &'a Session,
-    pub dst: PathBuf,
-    pub src: Option<PathBuf>,
-}
-
 /// Helper for adding many files to an archive.
 #[must_use = "must call build() to finish building the archive"]
 pub struct LlvmArchiveBuilder<'a> {
-    config: ArchiveConfig<'a>,
-    removals: Vec<String>,
+    sess: &'a Session,
+    dst: PathBuf,
     additions: Vec<Addition>,
-    src_archive: Option<Option<ArchiveRO>>,
 }
 
 enum Addition {
@@ -50,10 +43,6 @@
     }
 }
 
-fn archive_config<'a>(sess: &'a Session, output: &Path, input: Option<&Path>) -> ArchiveConfig<'a> {
-    ArchiveConfig { sess, dst: output.to_path_buf(), src: input.map(|p| p.to_path_buf()) }
-}
-
 /// Map machine type strings to values of LLVM's MachineTypes enum.
 fn llvm_machine_type(cpu: &str) -> LLVMMachineType {
     match cpu {
@@ -68,37 +57,8 @@
 impl<'a> ArchiveBuilder<'a> for LlvmArchiveBuilder<'a> {
     /// Creates a new static archive, ready for modifying the archive specified
     /// by `config`.
-    fn new(sess: &'a Session, output: &Path, input: Option<&Path>) -> LlvmArchiveBuilder<'a> {
-        let config = archive_config(sess, output, input);
-        LlvmArchiveBuilder {
-            config,
-            removals: Vec::new(),
-            additions: Vec::new(),
-            src_archive: None,
-        }
-    }
-
-    /// Removes a file from this archive
-    fn remove_file(&mut self, file: &str) {
-        self.removals.push(file.to_string());
-    }
-
-    /// Lists all files in an archive
-    fn src_files(&mut self) -> Vec<String> {
-        if self.src_archive().is_none() {
-            return Vec::new();
-        }
-
-        let archive = self.src_archive.as_ref().unwrap().as_ref().unwrap();
-
-        archive
-            .iter()
-            .filter_map(|child| child.ok())
-            .filter(is_relevant_child)
-            .filter_map(|child| child.name())
-            .filter(|name| !self.removals.iter().any(|x| x == name))
-            .map(|name| name.to_owned())
-            .collect()
+    fn new(sess: &'a Session, output: &Path) -> LlvmArchiveBuilder<'a> {
+        LlvmArchiveBuilder { sess, dst: output.to_path_buf(), additions: Vec::new() }
     }
 
     fn add_archive<F>(&mut self, archive: &Path, skip: F) -> io::Result<()>
@@ -129,13 +89,10 @@
 
     /// Combine the provided files, rlibs, and native libraries into a single
     /// `Archive`.
-    fn build(mut self) {
-        let kind = self.llvm_archive_kind().unwrap_or_else(|kind| {
-            self.config.sess.fatal(&format!("Don't know how to build archive of type: {}", kind))
-        });
-
-        if let Err(e) = self.build_with_llvm(kind) {
-            self.config.sess.fatal(&format!("failed to build archive: {}", e));
+    fn build(mut self) -> bool {
+        match self.build_with_llvm() {
+            Ok(any_members) => any_members,
+            Err(e) => self.sess.fatal(&format!("failed to build archive: {}", e)),
         }
     }
 
@@ -151,7 +108,7 @@
             output_path.with_extension("lib")
         };
 
-        let target = &self.config.sess.target;
+        let target = &self.sess.target;
         let mingw_gnu_toolchain = target.vendor == "pc"
             && target.os == "windows"
             && target.env == "gnu"
@@ -160,7 +117,7 @@
         let import_name_and_ordinal_vector: Vec<(String, Option<u16>)> = dll_imports
             .iter()
             .map(|import: &DllImport| {
-                if self.config.sess.target.arch == "x86" {
+                if self.sess.target.arch == "x86" {
                     (
                         LlvmArchiveBuilder::i686_decorated_name(import, mingw_gnu_toolchain),
                         import.ordinal,
@@ -197,11 +154,11 @@
             match std::fs::write(&def_file_path, def_file_content) {
                 Ok(_) => {}
                 Err(e) => {
-                    self.config.sess.fatal(&format!("Error writing .DEF file: {}", e));
+                    self.sess.fatal(&format!("Error writing .DEF file: {}", e));
                 }
             };
 
-            let dlltool = find_binutils_dlltool(self.config.sess);
+            let dlltool = find_binutils_dlltool(self.sess);
             let result = std::process::Command::new(dlltool)
                 .args([
                     "-d",
@@ -215,9 +172,9 @@
 
             match result {
                 Err(e) => {
-                    self.config.sess.fatal(&format!("Error calling dlltool: {}", e));
+                    self.sess.fatal(&format!("Error calling dlltool: {}", e));
                 }
-                Ok(output) if !output.status.success() => self.config.sess.fatal(&format!(
+                Ok(output) if !output.status.success() => self.sess.fatal(&format!(
                     "Dlltool could not create import library: {}\n{}",
                     String::from_utf8_lossy(&output.stdout),
                     String::from_utf8_lossy(&output.stderr)
@@ -263,13 +220,13 @@
                     output_path_z.as_ptr(),
                     ffi_exports.as_ptr(),
                     ffi_exports.len(),
-                    llvm_machine_type(&self.config.sess.target.arch) as u16,
-                    !self.config.sess.target.is_like_msvc,
+                    llvm_machine_type(&self.sess.target.arch) as u16,
+                    !self.sess.target.is_like_msvc,
                 )
             };
 
             if result == crate::llvm::LLVMRustResult::Failure {
-                self.config.sess.fatal(&format!(
+                self.sess.fatal(&format!(
                     "Error creating import library for {}: {}",
                     lib_name,
                     llvm::last_error().unwrap_or("unknown LLVM error".to_string())
@@ -278,7 +235,7 @@
         };
 
         self.add_archive(&output_path, |_| false).unwrap_or_else(|e| {
-            self.config.sess.fatal(&format!(
+            self.sess.fatal(&format!(
                 "failed to add native library {}: {}",
                 output_path.display(),
                 e
@@ -288,46 +245,19 @@
 }
 
 impl<'a> LlvmArchiveBuilder<'a> {
-    fn src_archive(&mut self) -> Option<&ArchiveRO> {
-        if let Some(ref a) = self.src_archive {
-            return a.as_ref();
-        }
-        let src = self.config.src.as_ref()?;
-        self.src_archive = Some(ArchiveRO::open(src).ok());
-        self.src_archive.as_ref().unwrap().as_ref()
-    }
+    fn build_with_llvm(&mut self) -> io::Result<bool> {
+        let kind = &*self.sess.target.archive_format;
+        let kind = kind.parse::<ArchiveKind>().map_err(|_| kind).unwrap_or_else(|kind| {
+            self.sess.fatal(&format!("Don't know how to build archive of type: {}", kind))
+        });
 
-    fn llvm_archive_kind(&self) -> Result<ArchiveKind, &str> {
-        let kind = &*self.config.sess.target.archive_format;
-        kind.parse().map_err(|_| kind)
-    }
-
-    fn build_with_llvm(&mut self, kind: ArchiveKind) -> io::Result<()> {
-        let removals = mem::take(&mut self.removals);
         let mut additions = mem::take(&mut self.additions);
         let mut strings = Vec::new();
         let mut members = Vec::new();
 
-        let dst = CString::new(self.config.dst.to_str().unwrap())?;
+        let dst = CString::new(self.dst.to_str().unwrap())?;
 
         unsafe {
-            if let Some(archive) = self.src_archive() {
-                for child in archive.iter() {
-                    let child = child.map_err(string_to_io_error)?;
-                    let Some(child_name) = child.name() else { continue };
-                    if removals.iter().any(|r| r == child_name) {
-                        continue;
-                    }
-
-                    let name = CString::new(child_name)?;
-                    members.push(llvm::LLVMRustArchiveMemberNew(
-                        ptr::null(),
-                        name.as_ptr(),
-                        Some(child.raw),
-                    ));
-                    strings.push(name);
-                }
-            }
             for addition in &mut additions {
                 match addition {
                     Addition::File { path, name_in_archive } => {
@@ -389,7 +319,7 @@
                 };
                 Err(io::Error::new(io::ErrorKind::Other, msg))
             } else {
-                Ok(())
+                Ok(!members.is_empty())
             };
             for member in members {
                 llvm::LLVMRustArchiveMemberFree(member);
diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs
index d0724ba..38402e0 100644
--- a/compiler/rustc_codegen_llvm/src/back/lto.rs
+++ b/compiler/rustc_codegen_llvm/src/back/lto.rs
@@ -354,14 +354,14 @@
     Ok(LtoModuleCodegen::Fat { module, _serialized_bitcode: serialized_bitcode })
 }
 
-crate struct Linker<'a>(&'a mut llvm::Linker<'a>);
+pub(crate) struct Linker<'a>(&'a mut llvm::Linker<'a>);
 
 impl<'a> Linker<'a> {
-    crate fn new(llmod: &'a llvm::Module) -> Self {
+    pub(crate) fn new(llmod: &'a llvm::Module) -> Self {
         unsafe { Linker(llvm::LLVMRustLinkerNew(llmod)) }
     }
 
-    crate fn add(&mut self, bytecode: &[u8]) -> Result<(), ()> {
+    pub(crate) fn add(&mut self, bytecode: &[u8]) -> Result<(), ()> {
         unsafe {
             if llvm::LLVMRustLinkerAdd(
                 self.0,
@@ -586,9 +586,21 @@
     // LTO-specific optimization passes that LLVM provides.
     //
     // This code is based off the code found in llvm's LTO code generator:
-    //      tools/lto/LTOCodeGenerator.cpp
+    //      llvm/lib/LTO/LTOCodeGenerator.cpp
     debug!("running the pass manager");
     unsafe {
+        if !llvm::LLVMRustHasModuleFlag(
+            module.module_llvm.llmod(),
+            "LTOPostLink".as_ptr().cast(),
+            11,
+        ) {
+            llvm::LLVMRustAddModuleFlag(
+                module.module_llvm.llmod(),
+                llvm::LLVMModFlagBehavior::Error,
+                "LTOPostLink\0".as_ptr().cast(),
+                1,
+            );
+        }
         if llvm_util::should_use_new_llvm_pass_manager(
             &config.new_llvm_pass_manager,
             &cgcx.target_arch,
diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs
index 99e3053..ab8874d 100644
--- a/compiler/rustc_codegen_llvm/src/back/write.rs
+++ b/compiler/rustc_codegen_llvm/src/back/write.rs
@@ -56,28 +56,24 @@
     file_type: llvm::FileType,
     self_profiler_ref: &SelfProfilerRef,
 ) -> Result<(), FatalError> {
+    debug!("write_output_file output={:?} dwo_output={:?}", output, dwo_output);
     unsafe {
         let output_c = path_to_c_string(output);
-        let result = if let Some(dwo_output) = dwo_output {
-            let dwo_output_c = path_to_c_string(dwo_output);
-            llvm::LLVMRustWriteOutputFile(
-                target,
-                pm,
-                m,
-                output_c.as_ptr(),
-                dwo_output_c.as_ptr(),
-                file_type,
-            )
+        let dwo_output_c;
+        let dwo_output_ptr = if let Some(dwo_output) = dwo_output {
+            dwo_output_c = path_to_c_string(dwo_output);
+            dwo_output_c.as_ptr()
         } else {
-            llvm::LLVMRustWriteOutputFile(
-                target,
-                pm,
-                m,
-                output_c.as_ptr(),
-                std::ptr::null(),
-                file_type,
-            )
+            std::ptr::null()
         };
+        let result = llvm::LLVMRustWriteOutputFile(
+            target,
+            pm,
+            m,
+            output_c.as_ptr(),
+            dwo_output_ptr,
+            file_type,
+        );
 
         // Record artifact sizes for self-profiling
         if result == llvm::LLVMRustResult::Success {
@@ -340,7 +336,7 @@
     }
     let level = match level {
         llvm::DiagnosticLevel::Error => Level::Error { lint: false },
-        llvm::DiagnosticLevel::Warning => Level::Warning,
+        llvm::DiagnosticLevel::Warning => Level::Warning(None),
         llvm::DiagnosticLevel::Note | llvm::DiagnosticLevel::Remark => Level::Note,
     };
     cgcx.diag_emitter.inline_asm_error(cookie as u32, msg, level, source);
@@ -467,7 +463,7 @@
     let llvm_selfprofiler =
         llvm_profiler.as_mut().map(|s| s as *mut _ as *mut c_void).unwrap_or(std::ptr::null_mut());
 
-    let extra_passes = config.passes.join(",");
+    let extra_passes = if !is_lto { config.passes.join(",") } else { "".to_string() };
 
     let llvm_plugins = config.llvm_plugins.join(",");
 
@@ -1040,7 +1036,8 @@
     // reason (see issue #90326 for historical background).
     let is_apple = cgcx.opts.target_triple.triple().contains("-ios")
         || cgcx.opts.target_triple.triple().contains("-darwin")
-        || cgcx.opts.target_triple.triple().contains("-tvos");
+        || cgcx.opts.target_triple.triple().contains("-tvos")
+        || cgcx.opts.target_triple.triple().contains("-watchos");
     if is_apple
         || cgcx.opts.target_triple.triple().starts_with("wasm")
         || cgcx.opts.target_triple.triple().starts_with("asmjs")
diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs
index 88b8795..c41a419 100644
--- a/compiler/rustc_codegen_llvm/src/builder.rs
+++ b/compiler/rustc_codegen_llvm/src/builder.rs
@@ -509,15 +509,20 @@
             OperandValue::Ref(place.llval, Some(llextra), place.align)
         } else if place.layout.is_llvm_immediate() {
             let mut const_llval = None;
+            let llty = place.layout.llvm_type(self);
             unsafe {
                 if let Some(global) = llvm::LLVMIsAGlobalVariable(place.llval) {
                     if llvm::LLVMIsGlobalConstant(global) == llvm::True {
-                        const_llval = llvm::LLVMGetInitializer(global);
+                        if let Some(init) = llvm::LLVMGetInitializer(global) {
+                            if self.val_ty(init) == llty {
+                                const_llval = Some(init);
+                            }
+                        }
                     }
                 }
             }
             let llval = const_llval.unwrap_or_else(|| {
-                let load = self.load(place.layout.llvm_type(self), place.llval, place.align);
+                let load = self.load(llty, place.llval, place.align);
                 if let abi::Abi::Scalar(scalar) = place.layout.abi {
                     scalar_load_metadata(self, load, scalar, place.layout, Size::ZERO);
                 }
@@ -1412,7 +1417,7 @@
         unsafe { llvm::LLVMBuildVAArg(self.llbuilder, list, ty, UNNAMED) }
     }
 
-    crate fn call_intrinsic(&mut self, intrinsic: &str, args: &[&'ll Value]) -> &'ll Value {
+    pub(crate) fn call_intrinsic(&mut self, intrinsic: &str, args: &[&'ll Value]) -> &'ll Value {
         let (ty, f) = self.cx.get_intrinsic(intrinsic);
         self.call(ty, f, args, None)
     }
diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs
index 4d3f3f3..5bbbfe9 100644
--- a/compiler/rustc_codegen_llvm/src/consts.rs
+++ b/compiler/rustc_codegen_llvm/src/consts.rs
@@ -212,11 +212,11 @@
 }
 
 impl<'ll> CodegenCx<'ll, '_> {
-    crate fn const_bitcast(&self, val: &'ll Value, ty: &'ll Type) -> &'ll Value {
+    pub(crate) fn const_bitcast(&self, val: &'ll Value, ty: &'ll Type) -> &'ll Value {
         unsafe { llvm::LLVMConstBitCast(val, ty) }
     }
 
-    crate fn static_addr_of_mut(
+    pub(crate) fn static_addr_of_mut(
         &self,
         cv: &'ll Value,
         align: Align,
@@ -241,7 +241,7 @@
         }
     }
 
-    crate fn get_static(&self, def_id: DefId) -> &'ll Value {
+    pub(crate) fn get_static(&self, def_id: DefId) -> &'ll Value {
         let instance = Instance::mono(self.tcx, def_id);
         if let Some(&g) = self.instances.borrow().get(&instance) {
             return g;
diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index d296ee3..c007728 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -326,11 +326,20 @@
         )
     }
 
+    if sess.opts.debugging_opts.virtual_function_elimination {
+        llvm::LLVMRustAddModuleFlag(
+            llmod,
+            llvm::LLVMModFlagBehavior::Error,
+            "Virtual Function Elim\0".as_ptr().cast(),
+            1,
+        );
+    }
+
     llmod
 }
 
 impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
-    crate fn new(
+    pub(crate) fn new(
         tcx: TyCtxt<'tcx>,
         codegen_unit: &'tcx CodegenUnit<'tcx>,
         llvm_module: &'ll crate::ModuleLlvm,
@@ -447,7 +456,7 @@
         }
     }
 
-    crate fn statics_to_rauw(&self) -> &RefCell<Vec<(&'ll Value, &'ll Value)>> {
+    pub(crate) fn statics_to_rauw(&self) -> &RefCell<Vec<(&'ll Value, &'ll Value)>> {
         &self.statics_to_rauw
     }
 
@@ -599,7 +608,7 @@
 }
 
 impl<'ll> CodegenCx<'ll, '_> {
-    crate fn get_intrinsic(&self, key: &str) -> (&'ll Type, &'ll Value) {
+    pub(crate) fn get_intrinsic(&self, key: &str) -> (&'ll Type, &'ll Value) {
         if let Some(v) = self.intrinsics.borrow().get(key).cloned() {
             return v;
         }
@@ -656,6 +665,7 @@
         let t_isize = self.type_isize();
         let t_f32 = self.type_f32();
         let t_f64 = self.type_f64();
+        let t_metadata = self.type_metadata();
 
         ifn!("llvm.wasm.trunc.unsigned.i32.f32", fn(t_f32) -> t_i32);
         ifn!("llvm.wasm.trunc.unsigned.i32.f64", fn(t_f64) -> t_i32);
@@ -881,21 +891,22 @@
             ifn!("llvm.instrprof.increment", fn(i8p, t_i64, t_i32, t_i32) -> void);
         }
 
-        ifn!("llvm.type.test", fn(i8p, self.type_metadata()) -> i1);
+        ifn!("llvm.type.test", fn(i8p, t_metadata) -> i1);
+        ifn!("llvm.type.checked.load", fn(i8p, t_i32, t_metadata) -> mk_struct! {i8p, i1});
 
         if self.sess().opts.debuginfo != DebugInfo::None {
-            ifn!("llvm.dbg.declare", fn(self.type_metadata(), self.type_metadata()) -> void);
-            ifn!("llvm.dbg.value", fn(self.type_metadata(), t_i64, self.type_metadata()) -> void);
+            ifn!("llvm.dbg.declare", fn(t_metadata, t_metadata) -> void);
+            ifn!("llvm.dbg.value", fn(t_metadata, t_i64, t_metadata) -> void);
         }
         None
     }
 
-    crate fn eh_catch_typeinfo(&self) -> &'ll Value {
+    pub(crate) fn eh_catch_typeinfo(&self) -> &'ll Value {
         if let Some(eh_catch_typeinfo) = self.eh_catch_typeinfo.get() {
             return eh_catch_typeinfo;
         }
         let tcx = self.tcx;
-        assert!(self.sess().target.is_like_emscripten);
+        assert!(self.sess().target.os == "emscripten");
         let eh_catch_typeinfo = match tcx.lang_items().eh_catch_typeinfo() {
             Some(def_id) => self.get_static(def_id),
             _ => {
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs
index 31a0924..5186aee 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs
@@ -5,11 +5,14 @@
 use crate::builder::Builder;
 use crate::common::CodegenCx;
 use crate::value::Value;
+use rustc_codegen_ssa::base::collect_debugger_visualizers_transitive;
 use rustc_codegen_ssa::traits::*;
+use rustc_hir::def_id::LOCAL_CRATE;
 use rustc_middle::bug;
-use rustc_session::config::DebugInfo;
+use rustc_session::config::{CrateType, DebugInfo};
 
 use rustc_span::symbol::sym;
+use rustc_span::DebuggerVisualizerType;
 
 /// Inserts a side-effect free instruction sequence that makes sure that the
 /// .debug_gdb_scripts global is referenced, so it isn't removed by the linker.
@@ -37,9 +40,33 @@
 
     section_var.unwrap_or_else(|| {
         let section_name = b".debug_gdb_scripts\0";
-        let section_contents = b"\x01gdb_load_rust_pretty_printers.py\0";
+        let mut section_contents = Vec::new();
+
+        // Add the pretty printers for the standard library first.
+        section_contents.extend_from_slice(b"\x01gdb_load_rust_pretty_printers.py\0");
+
+        // Next, add the pretty printers that were specified via the `#[debugger_visualizer]` attribute.
+        let visualizers = collect_debugger_visualizers_transitive(
+            cx.tcx,
+            DebuggerVisualizerType::GdbPrettyPrinter,
+        );
+        let crate_name = cx.tcx.crate_name(LOCAL_CRATE);
+        for (index, visualizer) in visualizers.iter().enumerate() {
+            // The initial byte `4` instructs GDB that the following pretty printer
+            // is defined inline as opposed to in a standalone file.
+            section_contents.extend_from_slice(b"\x04");
+            let vis_name = format!("pretty-printer-{}-{}\n", crate_name.as_str(), index);
+            section_contents.extend_from_slice(vis_name.as_bytes());
+            section_contents.extend_from_slice(&visualizer.src);
+
+            // The final byte `0` tells GDB that the pretty printer has been
+            // fully defined and can continue searching for additional
+            // pretty printers.
+            section_contents.extend_from_slice(b"\0");
+        }
 
         unsafe {
+            let section_contents = section_contents.as_slice();
             let llvm_type = cx.type_array(cx.type_i8(), section_contents.len() as u64);
 
             let section_var = cx
@@ -62,7 +89,32 @@
     let omit_gdb_pretty_printer_section =
         cx.tcx.sess.contains_name(cx.tcx.hir().krate_attrs(), sym::omit_gdb_pretty_printer_section);
 
+    // To ensure the section `__rustc_debug_gdb_scripts_section__` will not create
+    // ODR violations at link time, this section will not be emitted for rlibs since
+    // each rlib could produce a different set of visualizers that would be embedded
+    // in the `.debug_gdb_scripts` section. For that reason, we make sure that the
+    // section is only emitted for leaf crates.
+    let embed_visualizers = cx.sess().crate_types().iter().any(|&crate_type| match crate_type {
+        CrateType::Executable | CrateType::Dylib | CrateType::Cdylib | CrateType::Staticlib => {
+            // These are crate types for which we will embed pretty printers since they
+            // are treated as leaf crates.
+            true
+        }
+        CrateType::ProcMacro => {
+            // We could embed pretty printers for proc macro crates too but it does not
+            // seem like a good default, since this is a rare use case and we don't
+            // want to slow down the common case.
+            false
+        }
+        CrateType::Rlib => {
+            // As per the above description, embedding pretty printers for rlibs could
+            // lead to ODR violations so we skip this crate type as well.
+            false
+        }
+    });
+
     !omit_gdb_pretty_printer_section
         && cx.sess().opts.debuginfo != DebugInfo::None
         && cx.sess().target.emit_debug_gdb_scripts
+        && embed_visualizers
 }
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
index f2cf3b1..d5f39a4 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
@@ -30,26 +30,28 @@
 use rustc_index::vec::{Idx, IndexVec};
 use rustc_middle::bug;
 use rustc_middle::mir::{self, GeneratorLayout};
-use rustc_middle::ty::layout::LayoutOf;
-use rustc_middle::ty::layout::TyAndLayout;
+use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
 use rustc_middle::ty::subst::GenericArgKind;
-use rustc_middle::ty::{self, AdtKind, Instance, ParamEnv, Ty, TyCtxt, COMMON_VTABLE_ENTRIES};
-use rustc_session::config::{self, DebugInfo};
+use rustc_middle::ty::{
+    self, AdtKind, Instance, ParamEnv, PolyExistentialTraitRef, Ty, TyCtxt, Visibility,
+};
+use rustc_session::config::{self, DebugInfo, Lto};
 use rustc_span::symbol::Symbol;
-use rustc_span::FileNameDisplayPreference;
-use rustc_span::{self, SourceFile, SourceFileHash};
+use rustc_span::FileName;
+use rustc_span::{self, FileNameDisplayPreference, SourceFile};
+use rustc_symbol_mangling::typeid_for_trait_ref;
 use rustc_target::abi::{Align, Size};
 use smallvec::smallvec;
 use tracing::debug;
 
-use libc::{c_longlong, c_uint};
+use libc::{c_char, c_longlong, c_uint};
 use std::borrow::Cow;
-use std::collections::hash_map::Entry;
 use std::fmt::{self, Write};
 use std::hash::{Hash, Hasher};
 use std::iter;
 use std::path::{Path, PathBuf};
 use std::ptr;
+use tracing::instrument;
 
 impl PartialEq for llvm::Metadata {
     fn eq(&self, other: &Self) -> bool {
@@ -527,76 +529,103 @@
 }
 
 pub fn file_metadata<'ll>(cx: &CodegenCx<'ll, '_>, source_file: &SourceFile) -> &'ll DIFile {
-    debug!("file_metadata: file_name: {:?}", source_file.name);
+    let cache_key = Some((source_file.name_hash, source_file.src_hash));
+    return debug_context(cx)
+        .created_files
+        .borrow_mut()
+        .entry(cache_key)
+        .or_insert_with(|| alloc_new_file_metadata(cx, source_file));
 
-    let hash = Some(&source_file.src_hash);
-    let file_name = Some(source_file.name.prefer_remapped().to_string());
-    let directory = if source_file.is_real_file() && !source_file.is_imported() {
-        Some(
-            cx.sess()
-                .opts
-                .working_dir
-                .to_string_lossy(FileNameDisplayPreference::Remapped)
-                .to_string(),
-        )
-    } else {
-        // If the path comes from an upstream crate we assume it has been made
-        // independent of the compiler's working directory one way or another.
-        None
-    };
-    file_metadata_raw(cx, file_name, directory, hash)
+    #[instrument(skip(cx, source_file), level = "debug")]
+    fn alloc_new_file_metadata<'ll>(
+        cx: &CodegenCx<'ll, '_>,
+        source_file: &SourceFile,
+    ) -> &'ll DIFile {
+        debug!(?source_file.name);
+
+        let (directory, file_name) = match &source_file.name {
+            FileName::Real(filename) => {
+                let working_directory = &cx.sess().opts.working_dir;
+                debug!(?working_directory);
+
+                let filename = cx
+                    .sess()
+                    .source_map()
+                    .path_mapping()
+                    .to_embeddable_absolute_path(filename.clone(), working_directory);
+
+                // Construct the absolute path of the file
+                let abs_path = filename.remapped_path_if_available();
+                debug!(?abs_path);
+
+                if let Ok(rel_path) =
+                    abs_path.strip_prefix(working_directory.remapped_path_if_available())
+                {
+                    // If the compiler's working directory (which also is the DW_AT_comp_dir of
+                    // the compilation unit) is a prefix of the path we are about to emit, then
+                    // only emit the part relative to the working directory.
+                    // Because of path remapping we sometimes see strange things here: `abs_path`
+                    // might actually look like a relative path
+                    // (e.g. `<crate-name-and-version>/src/lib.rs`), so if we emit it without
+                    // taking the working directory into account, downstream tooling will
+                    // interpret it as `<working-directory>/<crate-name-and-version>/src/lib.rs`,
+                    // which makes no sense. Usually in such cases the working directory will also
+                    // be remapped to `<crate-name-and-version>` or some other prefix of the path
+                    // we are remapping, so we end up with
+                    // `<crate-name-and-version>/<crate-name-and-version>/src/lib.rs`.
+                    // By moving the working directory portion into the `directory` part of the
+                    // DIFile, we allow LLVM to emit just the relative path for DWARF, while
+                    // still emitting the correct absolute path for CodeView.
+                    (
+                        working_directory.to_string_lossy(FileNameDisplayPreference::Remapped),
+                        rel_path.to_string_lossy().into_owned(),
+                    )
+                } else {
+                    ("".into(), abs_path.to_string_lossy().into_owned())
+                }
+            }
+            other => ("".into(), other.prefer_remapped().to_string_lossy().into_owned()),
+        };
+
+        let hash_kind = match source_file.src_hash.kind {
+            rustc_span::SourceFileHashAlgorithm::Md5 => llvm::ChecksumKind::MD5,
+            rustc_span::SourceFileHashAlgorithm::Sha1 => llvm::ChecksumKind::SHA1,
+            rustc_span::SourceFileHashAlgorithm::Sha256 => llvm::ChecksumKind::SHA256,
+        };
+        let hash_value = hex_encode(source_file.src_hash.hash_bytes());
+
+        unsafe {
+            llvm::LLVMRustDIBuilderCreateFile(
+                DIB(cx),
+                file_name.as_ptr().cast(),
+                file_name.len(),
+                directory.as_ptr().cast(),
+                directory.len(),
+                hash_kind,
+                hash_value.as_ptr().cast(),
+                hash_value.len(),
+            )
+        }
+    }
 }
 
 pub fn unknown_file_metadata<'ll>(cx: &CodegenCx<'ll, '_>) -> &'ll DIFile {
-    file_metadata_raw(cx, None, None, None)
-}
+    debug_context(cx).created_files.borrow_mut().entry(None).or_insert_with(|| unsafe {
+        let file_name = "<unknown>";
+        let directory = "";
+        let hash_value = "";
 
-fn file_metadata_raw<'ll>(
-    cx: &CodegenCx<'ll, '_>,
-    file_name: Option<String>,
-    directory: Option<String>,
-    hash: Option<&SourceFileHash>,
-) -> &'ll DIFile {
-    let key = (file_name, directory);
-
-    match debug_context(cx).created_files.borrow_mut().entry(key) {
-        Entry::Occupied(o) => o.get(),
-        Entry::Vacant(v) => {
-            let (file_name, directory) = v.key();
-            debug!("file_metadata: file_name: {:?}, directory: {:?}", file_name, directory);
-
-            let file_name = file_name.as_deref().unwrap_or("<unknown>");
-            let directory = directory.as_deref().unwrap_or("");
-
-            let (hash_kind, hash_value) = match hash {
-                Some(hash) => {
-                    let kind = match hash.kind {
-                        rustc_span::SourceFileHashAlgorithm::Md5 => llvm::ChecksumKind::MD5,
-                        rustc_span::SourceFileHashAlgorithm::Sha1 => llvm::ChecksumKind::SHA1,
-                        rustc_span::SourceFileHashAlgorithm::Sha256 => llvm::ChecksumKind::SHA256,
-                    };
-                    (kind, hex_encode(hash.hash_bytes()))
-                }
-                None => (llvm::ChecksumKind::None, String::new()),
-            };
-
-            let file_metadata = unsafe {
-                llvm::LLVMRustDIBuilderCreateFile(
-                    DIB(cx),
-                    file_name.as_ptr().cast(),
-                    file_name.len(),
-                    directory.as_ptr().cast(),
-                    directory.len(),
-                    hash_kind,
-                    hash_value.as_ptr().cast(),
-                    hash_value.len(),
-                )
-            };
-
-            v.insert(file_metadata);
-            file_metadata
-        }
-    }
+        llvm::LLVMRustDIBuilderCreateFile(
+            DIB(cx),
+            file_name.as_ptr().cast(),
+            file_name.len(),
+            directory.as_ptr().cast(),
+            directory.len(),
+            llvm::ChecksumKind::None,
+            hash_value.as_ptr().cast(),
+            hash_value.len(),
+        )
+    })
 }
 
 trait MsvcBasicName {
@@ -1337,7 +1366,7 @@
             is_local_to_unit,
             global,
             None,
-            global_align.bytes() as u32,
+            global_align.bits() as u32,
         );
     }
 }
@@ -1364,7 +1393,7 @@
 
         tcx.vtable_entries(trait_ref)
     } else {
-        COMMON_VTABLE_ENTRIES
+        TyCtxt::COMMON_VTABLE_ENTRIES
     };
 
     // All function pointers are described as opaque pointers. This could be improved in the future
@@ -1440,6 +1469,84 @@
     .di_node
 }
 
+fn vcall_visibility_metadata<'ll, 'tcx>(
+    cx: &CodegenCx<'ll, 'tcx>,
+    ty: Ty<'tcx>,
+    trait_ref: Option<PolyExistentialTraitRef<'tcx>>,
+    vtable: &'ll Value,
+) {
+    enum VCallVisibility {
+        Public = 0,
+        LinkageUnit = 1,
+        TranslationUnit = 2,
+    }
+
+    let Some(trait_ref) = trait_ref else { return };
+
+    let trait_ref_self = trait_ref.with_self_ty(cx.tcx, ty);
+    let trait_ref_self = cx.tcx.erase_regions(trait_ref_self);
+    let trait_def_id = trait_ref_self.def_id();
+    let trait_vis = cx.tcx.visibility(trait_def_id);
+
+    let cgus = cx.sess().codegen_units();
+    let single_cgu = cgus == 1;
+
+    let lto = cx.sess().lto();
+
+    // Since LLVM requires full LTO for the virtual function elimination optimization to apply,
+    // only the `Lto::Fat` cases are relevant currently.
+    let vcall_visibility = match (lto, trait_vis, single_cgu) {
+        // If there is not LTO and the visibility in public, we have to assume that the vtable can
+        // be seen from anywhere. With multiple CGUs, the vtable is quasi-public.
+        (Lto::No | Lto::ThinLocal, Visibility::Public, _)
+        | (Lto::No, Visibility::Restricted(_) | Visibility::Invisible, false) => {
+            VCallVisibility::Public
+        }
+        // With LTO and a quasi-public visibility, the usages of the functions of the vtable are
+        // all known by the `LinkageUnit`.
+        // FIXME: LLVM only supports this optimization for `Lto::Fat` currently. Once it also
+        // supports `Lto::Thin` the `VCallVisibility` may have to be adjusted for those.
+        (Lto::Fat | Lto::Thin, Visibility::Public, _)
+        | (
+            Lto::ThinLocal | Lto::Thin | Lto::Fat,
+            Visibility::Restricted(_) | Visibility::Invisible,
+            false,
+        ) => VCallVisibility::LinkageUnit,
+        // If there is only one CGU, private vtables can only be seen by that CGU/translation unit
+        // and therefore we know of all usages of functions in the vtable.
+        (_, Visibility::Restricted(_) | Visibility::Invisible, true) => {
+            VCallVisibility::TranslationUnit
+        }
+    };
+
+    let trait_ref_typeid = typeid_for_trait_ref(cx.tcx, trait_ref);
+
+    unsafe {
+        let typeid = llvm::LLVMMDStringInContext(
+            cx.llcx,
+            trait_ref_typeid.as_ptr() as *const c_char,
+            trait_ref_typeid.as_bytes().len() as c_uint,
+        );
+        let v = [cx.const_usize(0), typeid];
+        llvm::LLVMRustGlobalAddMetadata(
+            vtable,
+            llvm::MD_type as c_uint,
+            llvm::LLVMValueAsMetadata(llvm::LLVMMDNodeInContext(
+                cx.llcx,
+                v.as_ptr(),
+                v.len() as c_uint,
+            )),
+        );
+        let vcall_visibility = llvm::LLVMValueAsMetadata(cx.const_u64(vcall_visibility as u64));
+        let vcall_visibility_metadata = llvm::LLVMMDNodeInContext2(cx.llcx, &vcall_visibility, 1);
+        llvm::LLVMGlobalSetMetadata(
+            vtable,
+            llvm::MetadataType::MD_vcall_visibility as c_uint,
+            vcall_visibility_metadata,
+        );
+    }
+}
+
 /// Creates debug information for the given vtable, which is for the
 /// given type.
 ///
@@ -1450,6 +1557,12 @@
     poly_trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
     vtable: &'ll Value,
 ) {
+    // FIXME(flip1995): The virtual function elimination optimization only works with full LTO in
+    // LLVM at the moment.
+    if cx.sess().opts.debugging_opts.virtual_function_elimination && cx.sess().lto() == Lto::Fat {
+        vcall_visibility_metadata(cx, ty, poly_trait_ref, vtable);
+    }
+
     if cx.dbg_cx.is_none() {
         return;
     }
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
index 6a16455..71699b5 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
@@ -31,14 +31,14 @@
 use rustc_session::config::{self, DebugInfo};
 use rustc_session::Session;
 use rustc_span::symbol::Symbol;
-use rustc_span::{self, BytePos, Pos, SourceFile, SourceFileAndLine, Span};
+use rustc_span::{self, BytePos, Pos, SourceFile, SourceFileAndLine, SourceFileHash, Span};
 use rustc_target::abi::Size;
 
 use libc::c_uint;
 use smallvec::SmallVec;
+use std::cell::OnceCell;
 use std::cell::RefCell;
 use std::iter;
-use std::lazy::OnceCell;
 use tracing::debug;
 
 mod create_scope_map;
@@ -61,7 +61,7 @@
     llcontext: &'ll llvm::Context,
     llmod: &'ll llvm::Module,
     builder: &'ll mut DIBuilder<'ll>,
-    created_files: RefCell<FxHashMap<(Option<String>, Option<String>), &'ll DIFile>>,
+    created_files: RefCell<FxHashMap<Option<(u128, SourceFileHash)>, &'ll DIFile>>,
 
     type_map: metadata::TypeMap<'ll, 'tcx>,
     namespace_map: RefCell<DefIdMap<&'ll DIScope>>,
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index 4407297..9f36474 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -406,6 +406,16 @@
         self.call_intrinsic("llvm.type.test", &[bitcast, typeid])
     }
 
+    fn type_checked_load(
+        &mut self,
+        llvtable: &'ll Value,
+        vtable_byte_offset: u64,
+        typeid: &'ll Value,
+    ) -> Self::Value {
+        let vtable_byte_offset = self.const_i32(vtable_byte_offset as i32);
+        self.call_intrinsic("llvm.type.checked.load", &[llvtable, vtable_byte_offset, typeid])
+    }
+
     fn va_start(&mut self, va_list: &'ll Value) -> &'ll Value {
         self.call_intrinsic("llvm.va_start", &[va_list])
     }
@@ -431,7 +441,7 @@
         bx.store(bx.const_i32(0), dest, ret_align);
     } else if wants_msvc_seh(bx.sess()) {
         codegen_msvc_try(bx, try_func, data, catch_func, dest);
-    } else if bx.sess().target.is_like_emscripten {
+    } else if bx.sess().target.os == "emscripten" {
         codegen_emcc_try(bx, try_func, data, catch_func, dest);
     } else {
         codegen_gnu_try(bx, try_func, data, catch_func, dest);
@@ -816,7 +826,7 @@
     span: Span,
 ) -> Result<&'ll Value, ()> {
     // macros for error handling:
-    #[cfg_attr(not(bootstrap), allow(unused_macro_rules))]
+    #[allow(unused_macro_rules)]
     macro_rules! emit_error {
         ($msg: tt) => {
             emit_error!($msg, )
@@ -1145,7 +1155,7 @@
         span: Span,
         args: &[OperandRef<'tcx, &'ll Value>],
     ) -> Result<&'ll Value, ()> {
-        #[cfg_attr(not(bootstrap), allow(unused_macro_rules))]
+        #[allow(unused_macro_rules)]
         macro_rules! emit_error {
             ($msg: tt) => {
                 emit_error!($msg, )
diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs
index 0bead46..6713a75 100644
--- a/compiler/rustc_codegen_llvm/src/lib.rs
+++ b/compiler/rustc_codegen_llvm/src/lib.rs
@@ -5,12 +5,10 @@
 //! This API is completely unstable and subject to change.
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
-#![feature(crate_visibility_modifier)]
 #![feature(let_chains)]
 #![feature(let_else)]
 #![feature(extern_types)]
 #![feature(once_cell)]
-#![feature(nll)]
 #![feature(iter_intersperse)]
 #![recursion_limit = "256"]
 #![allow(rustc::potential_query_instability)]
@@ -305,8 +303,8 @@
           local stack variable in the ABI.)
 
     basic
-        Generate stack canaries in functions with:
-        - local variables of `[T; N]` type, where `T` is byte-sized and `N` > 8.
+        Generate stack canaries in functions with local variables of `[T; N]`
+        type, where `T` is byte-sized and `N` >= 8.
 
     none
         Do not generate stack canaries.
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index 13baadd..b831423 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -381,9 +381,8 @@
 impl AtomicOrdering {
     pub fn from_generic(ao: rustc_codegen_ssa::common::AtomicOrdering) -> Self {
         match ao {
-            rustc_codegen_ssa::common::AtomicOrdering::NotAtomic => AtomicOrdering::NotAtomic,
             rustc_codegen_ssa::common::AtomicOrdering::Unordered => AtomicOrdering::Unordered,
-            rustc_codegen_ssa::common::AtomicOrdering::Monotonic => AtomicOrdering::Monotonic,
+            rustc_codegen_ssa::common::AtomicOrdering::Relaxed => AtomicOrdering::Monotonic,
             rustc_codegen_ssa::common::AtomicOrdering::Acquire => AtomicOrdering::Acquire,
             rustc_codegen_ssa::common::AtomicOrdering::Release => AtomicOrdering::Release,
             rustc_codegen_ssa::common::AtomicOrdering::AcquireRelease => {
@@ -443,6 +442,7 @@
     MD_nonnull = 11,
     MD_align = 17,
     MD_type = 19,
+    MD_vcall_visibility = 28,
     MD_noundef = 29,
 }
 
@@ -775,7 +775,7 @@
     }
 
     impl CounterMappingRegion {
-        crate fn code_region(
+        pub(crate) fn code_region(
             counter: coverage_map::Counter,
             file_id: u32,
             start_line: u32,
@@ -799,7 +799,7 @@
         // This function might be used in the future; the LLVM API is still evolving, as is coverage
         // support.
         #[allow(dead_code)]
-        crate fn branch_region(
+        pub(crate) fn branch_region(
             counter: coverage_map::Counter,
             false_counter: coverage_map::Counter,
             file_id: u32,
@@ -824,7 +824,7 @@
         // This function might be used in the future; the LLVM API is still evolving, as is coverage
         // support.
         #[allow(dead_code)]
-        crate fn expansion_region(
+        pub(crate) fn expansion_region(
             file_id: u32,
             expanded_file_id: u32,
             start_line: u32,
@@ -848,7 +848,7 @@
         // This function might be used in the future; the LLVM API is still evolving, as is coverage
         // support.
         #[allow(dead_code)]
-        crate fn skipped_region(
+        pub(crate) fn skipped_region(
             file_id: u32,
             start_line: u32,
             start_col: u32,
@@ -871,7 +871,7 @@
         // This function might be used in the future; the LLVM API is still evolving, as is coverage
         // support.
         #[allow(dead_code)]
-        crate fn gap_region(
+        pub(crate) fn gap_region(
             counter: coverage_map::Counter,
             file_id: u32,
             start_line: u32,
@@ -1068,6 +1068,7 @@
     pub fn LLVMReplaceAllUsesWith<'a>(OldVal: &'a Value, NewVal: &'a Value);
     pub fn LLVMSetMetadata<'a>(Val: &'a Value, KindID: c_uint, Node: &'a Value);
     pub fn LLVMGlobalSetMetadata<'a>(Val: &'a Value, KindID: c_uint, Metadata: &'a Metadata);
+    pub fn LLVMRustGlobalAddMetadata<'a>(Val: &'a Value, KindID: c_uint, Metadata: &'a Metadata);
     pub fn LLVMValueAsMetadata(Node: &Value) -> &Metadata;
 
     // Operations on constants of any type
@@ -1081,6 +1082,11 @@
         Vals: *const &'a Value,
         Count: c_uint,
     ) -> &'a Value;
+    pub fn LLVMMDNodeInContext2<'a>(
+        C: &'a Context,
+        Vals: *const &'a Metadata,
+        Count: size_t,
+    ) -> &'a Metadata;
     pub fn LLVMAddNamedMetadataOperand<'a>(M: &'a Module, Name: *const c_char, Val: &'a Value);
 
     // Operations on scalar constants
@@ -1937,6 +1943,7 @@
         name: *const c_char,
         value: u32,
     );
+    pub fn LLVMRustHasModuleFlag(M: &Module, name: *const c_char, len: size_t) -> bool;
 
     pub fn LLVMRustMetadataAsValue<'a>(C: &'a Context, MD: &'a Metadata) -> &'a Value;
 
diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs
index 7b407c9..ce6c6e3 100644
--- a/compiler/rustc_codegen_llvm/src/llvm_util.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs
@@ -218,15 +218,17 @@
     sess: &Session,
     features: &FxHashMap<&str, bool>,
 ) -> Option<&'static [&'static str]> {
-    for tied in tied_target_features(sess) {
-        // Tied features must be set to the same value, or not set at all
-        let mut tied_iter = tied.iter();
-        let enabled = features.get(tied_iter.next().unwrap());
-        if tied_iter.any(|f| enabled != features.get(f)) {
-            return Some(tied);
+    if !features.is_empty() {
+        for tied in tied_target_features(sess) {
+            // Tied features must be set to the same value, or not set at all
+            let mut tied_iter = tied.iter();
+            let enabled = features.get(tied_iter.next().unwrap());
+            if tied_iter.any(|f| enabled != features.get(f)) {
+                return Some(tied);
+            }
         }
     }
-    None
+    return None;
 }
 
 // Used to generate cfg variables and apply features
@@ -440,6 +442,7 @@
 
     // -Ctarget-features
     let supported_features = supported_target_features(sess);
+    let mut featsmap = FxHashMap::default();
     let feats = sess
         .opts
         .cg
@@ -485,35 +488,36 @@
                 }
                 diag.emit();
             }
-            Some((enable_disable, feature))
-        })
-        .collect::<SmallVec<[(char, &str); 8]>>();
 
-    if diagnostics {
-        // FIXME(nagisa): figure out how to not allocate a full hashset here.
-        let featmap = feats.iter().map(|&(flag, feat)| (feat, flag == '+')).collect();
-        if let Some(f) = check_tied_features(sess, &featmap) {
-            sess.err(&format!(
-                "target features {} must all be enabled or disabled together",
-                f.join(", ")
-            ));
-        }
+            if diagnostics {
+                // FIXME(nagisa): figure out how to not allocate a full hashset here.
+                featsmap.insert(feature, enable_disable == '+');
+            }
+
+            // rustc-specific features do not get passed down to LLVM…
+            if RUSTC_SPECIFIC_FEATURES.contains(&feature) {
+                return None;
+            }
+            // ... otherwise though we run through `to_llvm_features` when
+            // passing requests down to LLVM. This means that all in-language
+            // features also work on the command line instead of having two
+            // different names when the LLVM name and the Rust name differ.
+            Some(
+                to_llvm_features(sess, feature)
+                    .into_iter()
+                    .map(move |f| format!("{}{}", enable_disable, f)),
+            )
+        })
+        .flatten();
+    features.extend(feats);
+
+    if diagnostics && let Some(f) = check_tied_features(sess, &featsmap) {
+        sess.err(&format!(
+            "target features {} must all be enabled or disabled together",
+            f.join(", ")
+        ));
     }
 
-    features.extend(feats.into_iter().flat_map(|(enable_disable, feature)| {
-        // rustc-specific features do not get passed down to LLVM…
-        if RUSTC_SPECIFIC_FEATURES.contains(&feature) {
-            return SmallVec::<[_; 2]>::new();
-        }
-        // ... otherwise though we run through `to_llvm_features` when
-        // passing requests down to LLVM. This means that all in-language
-        // features also work on the command line instead of having two
-        // different names when the LLVM name and the Rust name differ.
-        to_llvm_features(sess, feature)
-            .into_iter()
-            .map(|f| format!("{}{}", enable_disable, f))
-            .collect()
-    }));
     features
 }
 
diff --git a/compiler/rustc_codegen_llvm/src/type_.rs b/compiler/rustc_codegen_llvm/src/type_.rs
index 21b77f7..cf2d3c4 100644
--- a/compiler/rustc_codegen_llvm/src/type_.rs
+++ b/compiler/rustc_codegen_llvm/src/type_.rs
@@ -39,33 +39,33 @@
 }
 
 impl<'ll> CodegenCx<'ll, '_> {
-    crate fn type_named_struct(&self, name: &str) -> &'ll Type {
+    pub(crate) fn type_named_struct(&self, name: &str) -> &'ll Type {
         let name = SmallCStr::new(name);
         unsafe { llvm::LLVMStructCreateNamed(self.llcx, name.as_ptr()) }
     }
 
-    crate fn set_struct_body(&self, ty: &'ll Type, els: &[&'ll Type], packed: bool) {
+    pub(crate) fn set_struct_body(&self, ty: &'ll Type, els: &[&'ll Type], packed: bool) {
         unsafe { llvm::LLVMStructSetBody(ty, els.as_ptr(), els.len() as c_uint, packed as Bool) }
     }
 
-    crate fn type_void(&self) -> &'ll Type {
+    pub(crate) fn type_void(&self) -> &'ll Type {
         unsafe { llvm::LLVMVoidTypeInContext(self.llcx) }
     }
 
-    crate fn type_metadata(&self) -> &'ll Type {
+    pub(crate) fn type_metadata(&self) -> &'ll Type {
         unsafe { llvm::LLVMRustMetadataTypeInContext(self.llcx) }
     }
 
     ///x Creates an integer type with the given number of bits, e.g., i24
-    crate fn type_ix(&self, num_bits: u64) -> &'ll Type {
+    pub(crate) fn type_ix(&self, num_bits: u64) -> &'ll Type {
         unsafe { llvm::LLVMIntTypeInContext(self.llcx, num_bits as c_uint) }
     }
 
-    crate fn type_vector(&self, ty: &'ll Type, len: u64) -> &'ll Type {
+    pub(crate) fn type_vector(&self, ty: &'ll Type, len: u64) -> &'ll Type {
         unsafe { llvm::LLVMVectorType(ty, len as c_uint) }
     }
 
-    crate fn func_params_types(&self, ty: &'ll Type) -> Vec<&'ll Type> {
+    pub(crate) fn func_params_types(&self, ty: &'ll Type) -> Vec<&'ll Type> {
         unsafe {
             let n_args = llvm::LLVMCountParamTypes(ty) as usize;
             let mut args = Vec::with_capacity(n_args);
@@ -75,11 +75,11 @@
         }
     }
 
-    crate fn type_bool(&self) -> &'ll Type {
+    pub(crate) fn type_bool(&self) -> &'ll Type {
         self.type_i8()
     }
 
-    crate fn type_int_from_ty(&self, t: ty::IntTy) -> &'ll Type {
+    pub(crate) fn type_int_from_ty(&self, t: ty::IntTy) -> &'ll Type {
         match t {
             ty::IntTy::Isize => self.type_isize(),
             ty::IntTy::I8 => self.type_i8(),
@@ -90,7 +90,7 @@
         }
     }
 
-    crate fn type_uint_from_ty(&self, t: ty::UintTy) -> &'ll Type {
+    pub(crate) fn type_uint_from_ty(&self, t: ty::UintTy) -> &'ll Type {
         match t {
             ty::UintTy::Usize => self.type_isize(),
             ty::UintTy::U8 => self.type_i8(),
@@ -101,14 +101,14 @@
         }
     }
 
-    crate fn type_float_from_ty(&self, t: ty::FloatTy) -> &'ll Type {
+    pub(crate) fn type_float_from_ty(&self, t: ty::FloatTy) -> &'ll Type {
         match t {
             ty::FloatTy::F32 => self.type_f32(),
             ty::FloatTy::F64 => self.type_f64(),
         }
     }
 
-    crate fn type_pointee_for_align(&self, align: Align) -> &'ll Type {
+    pub(crate) fn type_pointee_for_align(&self, align: Align) -> &'ll Type {
         // FIXME(eddyb) We could find a better approximation if ity.align < align.
         let ity = Integer::approximate_align(self, align);
         self.type_from_integer(ity)
@@ -116,7 +116,7 @@
 
     /// Return a LLVM type that has at most the required alignment,
     /// and exactly the required size, as a best-effort padding array.
-    crate fn type_padding_filler(&self, size: Size, align: Align) -> &'ll Type {
+    pub(crate) fn type_padding_filler(&self, size: Size, align: Align) -> &'ll Type {
         let unit = Integer::approximate_align(self, align);
         let size = size.bytes();
         let unit_size = unit.size().bytes();
@@ -124,11 +124,11 @@
         self.type_array(self.type_from_integer(unit), size / unit_size)
     }
 
-    crate fn type_variadic_func(&self, args: &[&'ll Type], ret: &'ll Type) -> &'ll Type {
+    pub(crate) fn type_variadic_func(&self, args: &[&'ll Type], ret: &'ll Type) -> &'ll Type {
         unsafe { llvm::LLVMFunctionType(ret, args.as_ptr(), args.len() as c_uint, True) }
     }
 
-    crate fn type_array(&self, ty: &'ll Type, len: u64) -> &'ll Type {
+    pub(crate) fn type_array(&self, ty: &'ll Type, len: u64) -> &'ll Type {
         unsafe { llvm::LLVMRustArrayType(ty, len) }
     }
 }
diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml
index 93b10a0..2fa66b2 100644
--- a/compiler/rustc_codegen_ssa/Cargo.toml
+++ b/compiler/rustc_codegen_ssa/Cargo.toml
@@ -14,8 +14,9 @@
 libc = "0.2.50"
 jobserver = "0.1.22"
 tempfile = "3.2"
-thorin-dwp = "0.2"
+thorin-dwp = "0.3"
 pathdiff = "0.2.0"
+serde_json = "1.0.59"
 snap = "1"
 smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
 regex = "1.4"
@@ -41,6 +42,6 @@
 rustc_session = { path = "../rustc_session" }
 
 [dependencies.object]
-version = "0.28.4"
+version = "0.29.0"
 default-features = false
 features = ["read_core", "elf", "macho", "pe", "unaligned", "archive", "write"]
diff --git a/compiler/rustc_codegen_ssa/src/back/archive.rs b/compiler/rustc_codegen_ssa/src/back/archive.rs
index a2f74b9..553486a 100644
--- a/compiler/rustc_codegen_ssa/src/back/archive.rs
+++ b/compiler/rustc_codegen_ssa/src/back/archive.rs
@@ -42,17 +42,15 @@
 }
 
 pub trait ArchiveBuilder<'a> {
-    fn new(sess: &'a Session, output: &Path, input: Option<&Path>) -> Self;
+    fn new(sess: &'a Session, output: &Path) -> Self;
 
     fn add_file(&mut self, path: &Path);
-    fn remove_file(&mut self, name: &str);
-    fn src_files(&mut self) -> Vec<String>;
 
     fn add_archive<F>(&mut self, archive: &Path, skip: F) -> io::Result<()>
     where
         F: FnMut(&str) -> bool + 'static;
 
-    fn build(self);
+    fn build(self) -> bool;
 
     fn inject_dll_import_lib(
         &mut self,
diff --git a/compiler/rustc_codegen_ssa/src/back/command.rs b/compiler/rustc_codegen_ssa/src/back/command.rs
index 17071ba..6c29692 100644
--- a/compiler/rustc_codegen_ssa/src/back/command.rs
+++ b/compiler/rustc_codegen_ssa/src/back/command.rs
@@ -105,12 +105,7 @@
             }
             Program::Lld(ref p, flavor) => {
                 let mut c = process::Command::new(p);
-                c.arg("-flavor").arg(match flavor {
-                    LldFlavor::Wasm => "wasm",
-                    LldFlavor::Ld => "gnu",
-                    LldFlavor::Link => "link",
-                    LldFlavor::Ld64 => "darwin",
-                });
+                c.arg("-flavor").arg(flavor.as_str());
                 if let LldFlavor::Wasm = flavor {
                     // LLVM expects host-specific formatting for @file
                     // arguments, but we always generate posix formatted files
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index 04ec1e7..ea83877 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -5,7 +5,7 @@
 use rustc_data_structures::temp_dir::MaybeTempDir;
 use rustc_errors::{ErrorGuaranteed, Handler};
 use rustc_fs_util::fix_windows_verbatim_for_gcc;
-use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
+use rustc_hir::def_id::CrateNum;
 use rustc_middle::middle::dependency_format::Linkage;
 use rustc_middle::middle::exported_symbols::SymbolExportKind;
 use rustc_session::config::{self, CFGuard, CrateType, DebugInfo, LdImpl, Strip};
@@ -18,6 +18,7 @@
 /// need out of the shared crate context before we get rid of it.
 use rustc_session::{filesearch, Session};
 use rustc_span::symbol::Symbol;
+use rustc_span::DebuggerVisualizerFile;
 use rustc_target::spec::crt_objects::{CrtObjects, CrtObjectsFallback};
 use rustc_target::spec::{LinkOutputKind, LinkerFlavor, LldFlavor, SplitDebuginfo};
 use rustc_target::spec::{PanicStrategy, RelocModel, RelroLevel, SanitizerSet, Target};
@@ -37,10 +38,11 @@
 use tempfile::Builder as TempFileBuilder;
 
 use std::borrow::Borrow;
+use std::cell::OnceCell;
+use std::collections::BTreeSet;
 use std::ffi::OsString;
 use std::fs::{File, OpenOptions};
 use std::io::{BufWriter, Write};
-use std::lazy::OnceCell;
 use std::ops::Deref;
 use std::path::{Path, PathBuf};
 use std::process::{ExitStatus, Output, Stdio};
@@ -268,7 +270,7 @@
 
     let lib_search_paths = archive_search_paths(sess);
 
-    let mut ab = <B as ArchiveBuilder>::new(sess, out_filename, None);
+    let mut ab = <B as ArchiveBuilder>::new(sess, out_filename);
 
     let trailing_metadata = match flavor {
         RlibFlavor::Normal => {
@@ -1001,10 +1003,14 @@
     let strip = strip_value(sess);
 
     if sess.target.is_like_osx {
-        match strip {
-            Strip::Debuginfo => strip_symbols_in_osx(sess, &out_filename, Some("-S")),
-            Strip::Symbols => strip_symbols_in_osx(sess, &out_filename, None),
-            Strip::None => {}
+        match (strip, crate_type) {
+            (Strip::Debuginfo, _) => strip_symbols_in_osx(sess, &out_filename, Some("-S")),
+            // Per the manpage, `-x` is the maximum safe strip level for dynamic libraries. (#93988)
+            (Strip::Symbols, CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro) => {
+                strip_symbols_in_osx(sess, &out_filename, Some("-x"))
+            }
+            (Strip::Symbols, _) => strip_symbols_in_osx(sess, &out_filename, None),
+            (Strip::None, _) => {}
         }
     }
 }
@@ -1950,7 +1956,7 @@
         add_local_native_libraries(cmd, sess, codegen_results);
     }
 
-    // Upstream rust libraries and their nobundle static libraries
+    // Upstream rust libraries and their non-bundled static libraries
     add_upstream_rust_crates::<B>(cmd, sess, codegen_results, crate_type, tmpdir);
 
     // Upstream dynamic native libraries linked with `#[link]` attributes at and `-l`
@@ -2025,7 +2031,7 @@
 
     add_link_script(cmd, sess, tmpdir, crate_type);
 
-    if sess.target.is_like_fuchsia && crate_type == CrateType::Executable {
+    if sess.target.os == "fuchsia" && crate_type == CrateType::Executable {
         let prefix = if sess.opts.debugging_opts.sanitizer.contains(SanitizerSet::ADDRESS) {
             "asan/"
         } else {
@@ -2045,7 +2051,7 @@
         cmd.no_crt_objects();
     }
 
-    if sess.target.is_like_emscripten {
+    if sess.target.os == "emscripten" {
         cmd.arg("-s");
         cmd.arg(if sess.panic_strategy() == PanicStrategy::Abort {
             "DISABLE_EXCEPTION_CATCHING=1"
@@ -2099,14 +2105,16 @@
     // Pass optimization flags down to the linker.
     cmd.optimize();
 
-    let debugger_visualizer_paths = if sess.target.is_like_msvc {
-        collect_debugger_visualizers(tmpdir, sess, &codegen_results.crate_info)
-    } else {
-        Vec::new()
-    };
+    // Gather the set of NatVis files, if any, and write them out to a temp directory.
+    let natvis_visualizers = collect_natvis_visualizers(
+        tmpdir,
+        sess,
+        &codegen_results.crate_info.local_crate_name,
+        &codegen_results.crate_info.natvis_debugger_visualizers,
+    );
 
-    // Pass debuginfo and strip flags down to the linker.
-    cmd.debuginfo(strip_value(sess), &debugger_visualizer_paths);
+    // Pass debuginfo, NatVis debugger visualizers and strip flags down to the linker.
+    cmd.debuginfo(strip_value(sess), &natvis_visualizers);
 
     // We want to prevent the compiler from accidentally leaking in any system libraries,
     // so by default we tell linkers not to link to any default libraries.
@@ -2125,43 +2133,33 @@
     add_rpath_args(cmd, sess, codegen_results, out_filename);
 }
 
-// Write the debugger visualizer files for each crate to the temp directory and gather the file paths.
-fn collect_debugger_visualizers(
+// Write the NatVis debugger visualizer files for each crate to the temp directory and gather the file paths.
+fn collect_natvis_visualizers(
     tmpdir: &Path,
     sess: &Session,
-    crate_info: &CrateInfo,
+    crate_name: &Symbol,
+    natvis_debugger_visualizers: &BTreeSet<DebuggerVisualizerFile>,
 ) -> Vec<PathBuf> {
-    let mut visualizer_paths = Vec::new();
-    let debugger_visualizers = &crate_info.debugger_visualizers;
-    let mut index = 0;
+    let mut visualizer_paths = Vec::with_capacity(natvis_debugger_visualizers.len());
 
-    for (&cnum, visualizers) in debugger_visualizers {
-        let crate_name = if cnum == LOCAL_CRATE {
-            crate_info.local_crate_name.as_str()
-        } else {
-            crate_info.crate_name[&cnum].as_str()
+    for (index, visualizer) in natvis_debugger_visualizers.iter().enumerate() {
+        let visualizer_out_file = tmpdir.join(format!("{}-{}.natvis", crate_name.as_str(), index));
+
+        match fs::write(&visualizer_out_file, &visualizer.src) {
+            Ok(()) => {
+                visualizer_paths.push(visualizer_out_file);
+            }
+            Err(error) => {
+                sess.warn(
+                    format!(
+                        "Unable to write debugger visualizer file `{}`: {} ",
+                        visualizer_out_file.display(),
+                        error
+                    )
+                    .as_str(),
+                );
+            }
         };
-
-        for visualizer in visualizers {
-            let visualizer_out_file = tmpdir.join(format!("{}-{}.natvis", crate_name, index));
-
-            match fs::write(&visualizer_out_file, &visualizer.src) {
-                Ok(()) => {
-                    visualizer_paths.push(visualizer_out_file.clone());
-                    index += 1;
-                }
-                Err(error) => {
-                    sess.warn(
-                        format!(
-                            "Unable to write debugger visualizer file `{}`: {} ",
-                            visualizer_out_file.display(),
-                            error
-                        )
-                        .as_str(),
-                    );
-                }
-            };
-        }
     }
     visualizer_paths
 }
@@ -2224,7 +2222,7 @@
                     // be added explicitly if necessary, see the error in `fn link_rlib`) compiled
                     // as an executable due to `--test`. Use whole-archive implicitly, like before
                     // the introduction of native lib modifiers.
-                    || (bundle != Some(false) && sess.opts.test)
+                    || (whole_archive == None && bundle != Some(false) && sess.opts.test)
                 {
                     cmd.link_whole_staticlib(
                         name,
@@ -2243,7 +2241,7 @@
     }
 }
 
-/// # Linking Rust crates and their nobundle static libraries
+/// # Linking Rust crates and their non-bundled static libraries
 ///
 /// Rust crates are not considered at all when creating an rlib output. All dependencies will be
 /// linked when producing the final output (instead of the intermediate rlib version).
@@ -2468,17 +2466,19 @@
         let name = &name[3..name.len() - 5]; // chop off lib/.rlib
 
         sess.prof.generic_activity_with_arg("link_altering_rlib", name).run(|| {
-            let mut archive = <B as ArchiveBuilder>::new(sess, &dst, Some(cratepath));
+            let canonical_name = name.replace('-', "_");
+            let upstream_rust_objects_already_included =
+                are_upstream_rust_objects_already_included(sess);
+            let is_builtins = sess.target.no_builtins
+                || !codegen_results.crate_info.is_no_builtins.contains(&cnum);
 
-            let mut any_objects = false;
-            for f in archive.src_files() {
+            let mut archive = <B as ArchiveBuilder>::new(sess, &dst);
+            if let Err(e) = archive.add_archive(cratepath, move |f| {
                 if f == METADATA_FILENAME {
-                    archive.remove_file(&f);
-                    continue;
+                    return true;
                 }
 
                 let canonical = f.replace('-', "_");
-                let canonical_name = name.replace('-', "_");
 
                 let is_rust_object =
                     canonical.starts_with(&canonical_name) && looks_like_rust_object_file(&f);
@@ -2492,23 +2492,20 @@
                 // file, then we don't need the object file as it's part of the
                 // LTO module. Note that `#![no_builtins]` is excluded from LTO,
                 // though, so we let that object file slide.
-                let skip_because_lto = are_upstream_rust_objects_already_included(sess)
-                    && is_rust_object
-                    && (sess.target.no_builtins
-                        || !codegen_results.crate_info.is_no_builtins.contains(&cnum));
+                let skip_because_lto =
+                    upstream_rust_objects_already_included && is_rust_object && is_builtins;
 
                 if skip_because_cfg_say_so || skip_because_lto {
-                    archive.remove_file(&f);
-                } else {
-                    any_objects = true;
+                    return true;
                 }
-            }
 
-            if !any_objects {
-                return;
+                false
+            }) {
+                sess.fatal(&format!("failed to build archive from rlib: {}", e));
             }
-            archive.build();
-            link_upstream(&dst);
+            if archive.build() {
+                link_upstream(&dst);
+            }
         });
     }
 
@@ -2608,7 +2605,7 @@
     let os = &sess.target.os;
     let llvm_target = &sess.target.llvm_target;
     if sess.target.vendor != "apple"
-        || !matches!(os.as_ref(), "ios" | "tvos")
+        || !matches!(os.as_ref(), "ios" | "tvos" | "watchos")
         || flavor != LinkerFlavor::Gcc
     {
         return;
@@ -2618,11 +2615,16 @@
         ("x86_64", "tvos") => "appletvsimulator",
         ("arm", "ios") => "iphoneos",
         ("aarch64", "ios") if llvm_target.contains("macabi") => "macosx",
-        ("aarch64", "ios") if llvm_target.contains("sim") => "iphonesimulator",
+        ("aarch64", "ios") if llvm_target.ends_with("-simulator") => "iphonesimulator",
         ("aarch64", "ios") => "iphoneos",
         ("x86", "ios") => "iphonesimulator",
         ("x86_64", "ios") if llvm_target.contains("macabi") => "macosx",
         ("x86_64", "ios") => "iphonesimulator",
+        ("x86_64", "watchos") => "watchsimulator",
+        ("arm64_32", "watchos") => "watchos",
+        ("aarch64", "watchos") if llvm_target.ends_with("-simulator") => "watchsimulator",
+        ("aarch64", "watchos") => "watchos",
+        ("arm", "watchos") => "watchos",
         _ => {
             sess.err(&format!("unsupported arch `{}` for os `{}`", arch, os));
             return;
@@ -2669,6 +2671,11 @@
             "macosx10.15"
                 if sdkroot.contains("iPhoneOS.platform")
                     || sdkroot.contains("iPhoneSimulator.platform") => {}
+            "watchos"
+                if sdkroot.contains("WatchSimulator.platform")
+                    || sdkroot.contains("MacOSX.platform") => {}
+            "watchsimulator"
+                if sdkroot.contains("WatchOS.platform") || sdkroot.contains("MacOSX.platform") => {}
             // Ignore `SDKROOT` if it's not a valid path.
             _ if !p.is_absolute() || p == Path::new("/") || !p.exists() => {}
             _ => return Ok(sdkroot),
@@ -2698,37 +2705,20 @@
         if let LinkerFlavor::Gcc = flavor {
             match ld_impl {
                 LdImpl::Lld => {
-                    if sess.target.lld_flavor == LldFlavor::Ld64 {
-                        let tools_path = sess.get_tools_search_paths(false);
-                        let ld64_exe = tools_path
-                            .into_iter()
-                            .map(|p| p.join("gcc-ld"))
-                            .map(|p| {
-                                p.join(if sess.host.is_like_windows { "ld64.exe" } else { "ld64" })
-                            })
-                            .find(|p| p.exists())
-                            .unwrap_or_else(|| sess.fatal("rust-lld (as ld64) not found"));
-                        cmd.cmd().arg({
-                            let mut arg = OsString::from("-fuse-ld=");
-                            arg.push(ld64_exe);
-                            arg
-                        });
-                    } else {
-                        let tools_path = sess.get_tools_search_paths(false);
-                        let lld_path = tools_path
-                            .into_iter()
-                            .map(|p| p.join("gcc-ld"))
-                            .find(|p| {
-                                p.join(if sess.host.is_like_windows { "ld.exe" } else { "ld" })
-                                    .exists()
-                            })
-                            .unwrap_or_else(|| sess.fatal("rust-lld (as ld) not found"));
-                        cmd.cmd().arg({
-                            let mut arg = OsString::from("-B");
-                            arg.push(lld_path);
-                            arg
-                        });
-                    }
+                    let tools_path = sess.get_tools_search_paths(false);
+                    let gcc_ld_dir = tools_path
+                        .into_iter()
+                        .map(|p| p.join("gcc-ld"))
+                        .find(|p| {
+                            p.join(if sess.host.is_like_windows { "ld.exe" } else { "ld" }).exists()
+                        })
+                        .unwrap_or_else(|| sess.fatal("rust-lld (as ld) not found"));
+                    cmd.arg({
+                        let mut arg = OsString::from("-B");
+                        arg.push(gcc_ld_dir);
+                        arg
+                    });
+                    cmd.arg(format!("-Wl,-rustc-lld-flavor={}", sess.target.lld_flavor.as_str()));
                 }
             }
         } else {
diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs
index 2a71377..b5b6394 100644
--- a/compiler/rustc_codegen_ssa/src/back/linker.rs
+++ b/compiler/rustc_codegen_ssa/src/back/linker.rs
@@ -14,7 +14,6 @@
 use rustc_middle::middle::dependency_format::Linkage;
 use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo, SymbolExportKind};
 use rustc_middle::ty::TyCtxt;
-use rustc_serialize::{json, Encoder};
 use rustc_session::config::{self, CrateType, DebugInfo, LinkerPluginLto, Lto, OptLevel, Strip};
 use rustc_session::Session;
 use rustc_span::symbol::Symbol;
@@ -183,7 +182,7 @@
     fn optimize(&mut self);
     fn pgo_gen(&mut self);
     fn control_flow_guard(&mut self);
-    fn debuginfo(&mut self, strip: Strip, debugger_visualizers: &[PathBuf]);
+    fn debuginfo(&mut self, strip: Strip, natvis_debugger_visualizers: &[PathBuf]);
     fn no_crt_objects(&mut self);
     fn no_default_libraries(&mut self);
     fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType, symbols: &[String]);
@@ -915,7 +914,7 @@
         self.cmd.arg("/guard:cf");
     }
 
-    fn debuginfo(&mut self, strip: Strip, debugger_visualizers: &[PathBuf]) {
+    fn debuginfo(&mut self, strip: Strip, natvis_debugger_visualizers: &[PathBuf]) {
         match strip {
             Strip::None => {
                 // This will cause the Microsoft linker to generate a PDB file
@@ -944,7 +943,7 @@
                 }
 
                 // This will cause the Microsoft linker to embed .natvis info for all crates into the PDB file
-                for path in debugger_visualizers {
+                for path in natvis_debugger_visualizers {
                     let mut arg = OsString::from("/NATVIS:");
                     arg.push(path);
                     self.cmd.arg(arg);
@@ -1121,8 +1120,6 @@
             OptLevel::Size => "-Os",
             OptLevel::SizeMin => "-Oz",
         });
-        // Unusable until https://github.com/rust-lang/rust/issues/38454 is resolved
-        self.cmd.args(&["--memory-init-file", "0"]);
     }
 
     fn pgo_gen(&mut self) {
@@ -1135,15 +1132,15 @@
         // Preserve names or generate source maps depending on debug info
         self.cmd.arg(match self.sess.opts.debuginfo {
             DebugInfo::None => "-g0",
-            DebugInfo::Limited => "-g3",
-            DebugInfo::Full => "-g4",
+            DebugInfo::Limited => "--profiling-funcs",
+            DebugInfo::Full => "-g",
         });
     }
 
     fn no_crt_objects(&mut self) {}
 
     fn no_default_libraries(&mut self) {
-        self.cmd.args(&["-s", "DEFAULT_LIBRARY_FUNCS_TO_INCLUDE=[]"]);
+        self.cmd.arg("-nodefaultlibs");
     }
 
     fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) {
@@ -1152,21 +1149,12 @@
         self.cmd.arg("-s");
 
         let mut arg = OsString::from("EXPORTED_FUNCTIONS=");
-        let mut encoded = String::new();
-
-        {
-            let mut encoder = json::Encoder::new(&mut encoded);
-            let res = encoder.emit_seq(symbols.len(), |encoder| {
-                for (i, sym) in symbols.iter().enumerate() {
-                    encoder.emit_seq_elt(i, |encoder| encoder.emit_str(&("_".to_owned() + sym)))?;
-                }
-                Ok(())
-            });
-            if let Err(e) = res {
-                self.sess.fatal(&format!("failed to encode exported symbols: {}", e));
-            }
-        }
+        let encoded = serde_json::to_string(
+            &symbols.iter().map(|sym| "_".to_owned() + sym).collect::<Vec<_>>(),
+        )
+        .unwrap();
         debug!("{}", encoded);
+
         arg.push(encoded);
 
         self.cmd.arg(arg);
diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs
index 6aa96f9..3dd607a 100644
--- a/compiler/rustc_codegen_ssa/src/back/metadata.rs
+++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs
@@ -130,7 +130,7 @@
     };
 
     let mut file = write::Object::new(binary_format, architecture, endianness);
-    match architecture {
+    let e_flags = match architecture {
         Architecture::Mips => {
             let arch = match sess.target.options.cpu.as_ref() {
                 "mips1" => elf::EF_MIPS_ARCH_1,
@@ -149,7 +149,7 @@
             if sess.target.options.cpu.contains("r6") {
                 e_flags |= elf::EF_MIPS_NAN2008;
             }
-            file.flags = FileFlags::Elf { e_flags };
+            e_flags
         }
         Architecture::Mips64 => {
             // copied from `mips64el-linux-gnuabi64-gcc foo.c -c`
@@ -160,17 +160,26 @@
                 } else {
                     elf::EF_MIPS_ARCH_64R2
                 };
-            file.flags = FileFlags::Elf { e_flags };
+            e_flags
         }
         Architecture::Riscv64 if sess.target.options.features.contains("+d") => {
             // copied from `riscv64-linux-gnu-gcc foo.c -c`, note though
             // that the `+d` target feature represents whether the double
             // float abi is enabled.
             let e_flags = elf::EF_RISCV_RVC | elf::EF_RISCV_FLOAT_ABI_DOUBLE;
-            file.flags = FileFlags::Elf { e_flags };
+            e_flags
         }
-        _ => {}
+        _ => 0,
     };
+    // adapted from LLVM's `MCELFObjectTargetWriter::getOSABI`
+    let os_abi = match sess.target.options.os.as_ref() {
+        "hermit" => elf::ELFOSABI_STANDALONE,
+        "freebsd" => elf::ELFOSABI_FREEBSD,
+        "solaris" => elf::ELFOSABI_SOLARIS,
+        _ => elf::ELFOSABI_NONE,
+    };
+    let abi_version = 0;
+    file.flags = FileFlags::Elf { os_abi, abi_version, e_flags };
     Some(file)
 }
 
diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs
index 88293de..632f07c 100644
--- a/compiler/rustc_codegen_ssa/src/back/write.rs
+++ b/compiler/rustc_codegen_ssa/src/back/write.rs
@@ -494,12 +494,12 @@
     let _timer = sess.timer("copy_all_cgu_workproducts_to_incr_comp_cache_dir");
 
     for module in compiled_modules.modules.iter().filter(|m| m.kind == ModuleKind::Regular) {
-        let path = module.object.as_ref().cloned();
-
-        if let Some((id, product)) =
-            copy_cgu_workproduct_to_incr_comp_cache_dir(sess, &module.name, &path)
-        {
-            work_products.insert(id, product);
+        if let Some(path) = &module.object {
+            if let Some((id, product)) =
+                copy_cgu_workproduct_to_incr_comp_cache_dir(sess, &module.name, path)
+            {
+                work_products.insert(id, product);
+            }
         }
     }
 
@@ -853,35 +853,31 @@
     module: CachedModuleCodegen,
     module_config: &ModuleConfig,
 ) -> WorkItemResult<B> {
-    let incr_comp_session_dir = cgcx.incr_comp_session_dir.as_ref().unwrap();
-    let mut object = None;
-    if let Some(saved_file) = module.source.saved_file {
-        let obj_out = cgcx.output_filenames.temp_path(OutputType::Object, Some(&module.name));
-        object = Some(obj_out.clone());
-        let source_file = in_incr_comp_dir(&incr_comp_session_dir, &saved_file);
-        debug!(
-            "copying pre-existing module `{}` from {:?} to {}",
-            module.name,
-            source_file,
-            obj_out.display()
-        );
-        if let Err(err) = link_or_copy(&source_file, &obj_out) {
-            let diag_handler = cgcx.create_diag_handler();
-            diag_handler.err(&format!(
-                "unable to copy {} to {}: {}",
-                source_file.display(),
-                obj_out.display(),
-                err
-            ));
-        }
-    }
+    assert!(module_config.emit_obj != EmitObj::None);
 
-    assert_eq!(object.is_some(), module_config.emit_obj != EmitObj::None);
+    let incr_comp_session_dir = cgcx.incr_comp_session_dir.as_ref().unwrap();
+    let obj_out = cgcx.output_filenames.temp_path(OutputType::Object, Some(&module.name));
+    let source_file = in_incr_comp_dir(&incr_comp_session_dir, &module.source.saved_file);
+    debug!(
+        "copying pre-existing module `{}` from {:?} to {}",
+        module.name,
+        source_file,
+        obj_out.display()
+    );
+    if let Err(err) = link_or_copy(&source_file, &obj_out) {
+        let diag_handler = cgcx.create_diag_handler();
+        diag_handler.err(&format!(
+            "unable to copy {} to {}: {}",
+            source_file.display(),
+            obj_out.display(),
+            err
+        ));
+    }
 
     WorkItemResult::Compiled(CompiledModule {
         name: module.name,
         kind: ModuleKind::Regular,
-        object,
+        object: Some(obj_out),
         dwarf_object: None,
         bytecode: None,
     })
@@ -1765,7 +1761,7 @@
 
                     let mut err = match level {
                         Level::Error { lint: false } => sess.struct_err(msg).forget_guarantee(),
-                        Level::Warning => sess.struct_warn(msg),
+                        Level::Warning(_) => sess.struct_warn(msg),
                         Level::Note => sess.struct_note_without_error(msg),
                         _ => bug!("Invalid inline asm diagnostic level"),
                     };
diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs
index 7b7e092..7e2e85e 100644
--- a/compiler/rustc_codegen_ssa/src/base.rs
+++ b/compiler/rustc_codegen_ssa/src/base.rs
@@ -15,8 +15,9 @@
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry};
 
+use rustc_data_structures::sync::par_iter;
 #[cfg(parallel_compiler)]
-use rustc_data_structures::sync::{par_iter, ParallelIterator};
+use rustc_data_structures::sync::ParallelIterator;
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LOCAL_CRATE};
 use rustc_hir::lang_items::LangItem;
@@ -30,11 +31,13 @@
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
 use rustc_session::cgu_reuse_tracker::CguReuse;
-use rustc_session::config::{self, EntryFnType, OutputType};
+use rustc_session::config::{self, CrateType, EntryFnType, OutputType};
 use rustc_session::Session;
 use rustc_span::symbol::sym;
+use rustc_span::{DebuggerVisualizerFile, DebuggerVisualizerType};
 use rustc_target::abi::{Align, VariantIdx};
 
+use std::collections::BTreeSet;
 use std::convert::TryFrom;
 use std::ops::{Deref, DerefMut};
 use std::time::{Duration, Instant};
@@ -213,11 +216,12 @@
             let mut result = None;
             for i in 0..src_layout.fields.count() {
                 let src_f = src_layout.field(bx.cx(), i);
-                assert_eq!(src_layout.fields.offset(i).bytes(), 0);
-                assert_eq!(dst_layout.fields.offset(i).bytes(), 0);
                 if src_f.is_zst() {
                     continue;
                 }
+
+                assert_eq!(src_layout.fields.offset(i).bytes(), 0);
+                assert_eq!(dst_layout.fields.offset(i).bytes(), 0);
                 assert_eq!(src_layout.size, src_f.size);
 
                 let dst_f = dst_layout.field(bx.cx(), i);
@@ -486,6 +490,29 @@
     }
 }
 
+/// This function returns all of the debugger visualizers specified for the
+/// current crate as well as all upstream crates transitively that match the
+/// `visualizer_type` specified.
+pub fn collect_debugger_visualizers_transitive(
+    tcx: TyCtxt<'_>,
+    visualizer_type: DebuggerVisualizerType,
+) -> BTreeSet<DebuggerVisualizerFile> {
+    tcx.debugger_visualizers(LOCAL_CRATE)
+        .iter()
+        .chain(
+            tcx.crates(())
+                .iter()
+                .filter(|&cnum| {
+                    let used_crate_source = tcx.used_crate_source(*cnum);
+                    used_crate_source.rlib.is_some() || used_crate_source.rmeta.is_some()
+                })
+                .flat_map(|&cnum| tcx.debugger_visualizers(cnum)),
+        )
+        .filter(|visualizer| visualizer.visualizer_type == visualizer_type)
+        .cloned()
+        .collect::<BTreeSet<_>>()
+}
+
 pub fn codegen_crate<B: ExtraBackendMethods>(
     backend: B,
     tcx: TyCtxt<'_>,
@@ -607,6 +634,14 @@
         second_half.iter().rev().interleave(first_half).copied().collect()
     };
 
+    // Calculate the CGU reuse
+    let cgu_reuse = tcx.sess.time("find_cgu_reuse", || {
+        codegen_units.iter().map(|cgu| determine_cgu_reuse(tcx, &cgu)).collect::<Vec<_>>()
+    });
+
+    let mut total_codegen_time = Duration::new(0, 0);
+    let start_rss = tcx.sess.time_passes().then(|| get_resident_set_size());
+
     // The non-parallel compiler can only translate codegen units to LLVM IR
     // on a single thread, leading to a staircase effect where the N LLVM
     // threads have to wait on the single codegen threads to generate work
@@ -617,8 +652,7 @@
     // This likely is a temporary measure. Once we don't have to support the
     // non-parallel compiler anymore, we can compile CGUs end-to-end in
     // parallel and get rid of the complicated scheduling logic.
-    #[cfg(parallel_compiler)]
-    let pre_compile_cgus = |cgu_reuse: &[CguReuse]| {
+    let mut pre_compiled_cgus = if cfg!(parallel_compiler) {
         tcx.sess.time("compile_first_CGU_batch", || {
             // Try to find one CGU to compile per thread.
             let cgus: Vec<_> = cgu_reuse
@@ -638,48 +672,31 @@
                 })
                 .collect();
 
-            (pre_compiled_cgus, start_time.elapsed())
+            total_codegen_time += start_time.elapsed();
+
+            pre_compiled_cgus
         })
+    } else {
+        FxHashMap::default()
     };
 
-    #[cfg(not(parallel_compiler))]
-    let pre_compile_cgus = |_: &[CguReuse]| (FxHashMap::default(), Duration::new(0, 0));
-
-    let mut cgu_reuse = Vec::new();
-    let mut pre_compiled_cgus: Option<FxHashMap<usize, _>> = None;
-    let mut total_codegen_time = Duration::new(0, 0);
-    let start_rss = tcx.sess.time_passes().then(|| get_resident_set_size());
-
     for (i, cgu) in codegen_units.iter().enumerate() {
         ongoing_codegen.wait_for_signal_to_codegen_item();
         ongoing_codegen.check_for_errors(tcx.sess);
 
-        // Do some setup work in the first iteration
-        if pre_compiled_cgus.is_none() {
-            // Calculate the CGU reuse
-            cgu_reuse = tcx.sess.time("find_cgu_reuse", || {
-                codegen_units.iter().map(|cgu| determine_cgu_reuse(tcx, &cgu)).collect()
-            });
-            // Pre compile some CGUs
-            let (compiled_cgus, codegen_time) = pre_compile_cgus(&cgu_reuse);
-            pre_compiled_cgus = Some(compiled_cgus);
-            total_codegen_time += codegen_time;
-        }
-
         let cgu_reuse = cgu_reuse[i];
         tcx.sess.cgu_reuse_tracker.set_actual_reuse(cgu.name().as_str(), cgu_reuse);
 
         match cgu_reuse {
             CguReuse::No => {
-                let (module, cost) =
-                    if let Some(cgu) = pre_compiled_cgus.as_mut().unwrap().remove(&i) {
-                        cgu
-                    } else {
-                        let start_time = Instant::now();
-                        let module = backend.compile_codegen_unit(tcx, cgu.name());
-                        total_codegen_time += start_time.elapsed();
-                        module
-                    };
+                let (module, cost) = if let Some(cgu) = pre_compiled_cgus.remove(&i) {
+                    cgu
+                } else {
+                    let start_time = Instant::now();
+                    let module = backend.compile_codegen_unit(tcx, cgu.name());
+                    total_codegen_time += start_time.elapsed();
+                    module
+                };
                 // This will unwind if there are errors, which triggers our `AbortCodegenOnDrop`
                 // guard. Unfortunately, just skipping the `submit_codegened_module_to_llvm` makes
                 // compilation hang on post-monomorphization errors.
@@ -700,7 +717,7 @@
                     &ongoing_codegen.coordinator_send,
                     CachedModuleCodegen {
                         name: cgu.name().to_string(),
-                        source: cgu.work_product(tcx),
+                        source: cgu.previous_work_product(tcx),
                     },
                 );
                 true
@@ -711,7 +728,7 @@
                     &ongoing_codegen.coordinator_send,
                     CachedModuleCodegen {
                         name: cgu.name().to_string(),
-                        source: cgu.work_product(tcx),
+                        source: cgu.previous_work_product(tcx),
                     },
                 );
                 true
@@ -847,13 +864,8 @@
             missing_lang_items: Default::default(),
             dependency_formats: tcx.dependency_formats(()).clone(),
             windows_subsystem,
-            debugger_visualizers: Default::default(),
+            natvis_debugger_visualizers: Default::default(),
         };
-        let debugger_visualizers = tcx.debugger_visualizers(LOCAL_CRATE).clone();
-        if !debugger_visualizers.is_empty() {
-            info.debugger_visualizers.insert(LOCAL_CRATE, debugger_visualizers);
-        }
-
         let lang_items = tcx.lang_items();
 
         let crates = tcx.crates(());
@@ -891,14 +903,29 @@
             let missing =
                 missing.iter().cloned().filter(|&l| lang_items::required(tcx, l)).collect();
             info.missing_lang_items.insert(cnum, missing);
+        }
 
-            // Only include debugger visualizer files from crates that will be statically linked.
-            if used_crate_source.rlib.is_some() || used_crate_source.rmeta.is_some() {
-                let debugger_visualizers = tcx.debugger_visualizers(cnum).clone();
-                if !debugger_visualizers.is_empty() {
-                    info.debugger_visualizers.insert(cnum, debugger_visualizers);
-                }
+        let embed_visualizers = tcx.sess.crate_types().iter().any(|&crate_type| match crate_type {
+            CrateType::Executable | CrateType::Dylib | CrateType::Cdylib => {
+                // These are crate types for which we invoke the linker and can embed
+                // NatVis visualizers.
+                true
             }
+            CrateType::ProcMacro => {
+                // We could embed NatVis for proc macro crates too (to improve the debugging
+                // experience for them) but it does not seem like a good default, since
+                // this is a rare use case and we don't want to slow down the common case.
+                false
+            }
+            CrateType::Staticlib | CrateType::Rlib => {
+                // We don't invoke the linker for these, so we don't need to collect the NatVis for them.
+                false
+            }
+        });
+
+        if tcx.sess.target.is_like_msvc && embed_visualizers {
+            info.natvis_debugger_visualizers =
+                collect_debugger_visualizers_transitive(tcx, DebuggerVisualizerType::Natvis);
         }
 
         info
diff --git a/compiler/rustc_codegen_ssa/src/common.rs b/compiler/rustc_codegen_ssa/src/common.rs
index 1574b30..8ca1a60 100644
--- a/compiler/rustc_codegen_ssa/src/common.rs
+++ b/compiler/rustc_codegen_ssa/src/common.rs
@@ -11,6 +11,7 @@
 use crate::base;
 use crate::traits::*;
 
+#[derive(Copy, Clone)]
 pub enum IntPredicate {
     IntEQ,
     IntNE,
@@ -24,6 +25,7 @@
     IntSLE,
 }
 
+#[derive(Copy, Clone)]
 pub enum RealPredicate {
     RealPredicateFalse,
     RealOEQ,
@@ -43,6 +45,7 @@
     RealPredicateTrue,
 }
 
+#[derive(Copy, Clone)]
 pub enum AtomicRmwBinOp {
     AtomicXchg,
     AtomicAdd,
@@ -57,17 +60,17 @@
     AtomicUMin,
 }
 
+#[derive(Copy, Clone)]
 pub enum AtomicOrdering {
-    NotAtomic,
     Unordered,
-    Monotonic,
-    // Consume,  // Not specified yet.
+    Relaxed,
     Acquire,
     Release,
     AcquireRelease,
     SequentiallyConsistent,
 }
 
+#[derive(Copy, Clone)]
 pub enum SynchronizationScope {
     SingleThread,
     CrossThread,
diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
index ae43464..8755d91 100644
--- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
+++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
@@ -180,7 +180,7 @@
             if cpp_like_debuginfo {
                 output.push_str("array$<");
                 push_debuginfo_type_name(tcx, inner_type, true, output, visited);
-                match len.val() {
+                match len.kind() {
                     ty::ConstKind::Param(param) => write!(output, ",{}>", param.name).unwrap(),
                     _ => write!(output, ",{}>", len.eval_usize(tcx, ty::ParamEnv::reveal_all()))
                         .unwrap(),
@@ -188,7 +188,7 @@
             } else {
                 output.push('[');
                 push_debuginfo_type_name(tcx, inner_type, true, output, visited);
-                match len.val() {
+                match len.kind() {
                     ty::ConstKind::Param(param) => write!(output, "; {}]", param.name).unwrap(),
                     _ => write!(output, "; {}]", len.eval_usize(tcx, ty::ParamEnv::reveal_all()))
                         .unwrap(),
@@ -679,7 +679,7 @@
 }
 
 fn push_const_param<'tcx>(tcx: TyCtxt<'tcx>, ct: ty::Const<'tcx>, output: &mut String) {
-    match ct.val() {
+    match ct.kind() {
         ty::ConstKind::Param(param) => {
             write!(output, "{}", param.name)
         }
@@ -703,15 +703,19 @@
                 // but we get a deterministic, virtually unique value for the constant.
                 let hcx = &mut tcx.create_stable_hashing_context();
                 let mut hasher = StableHasher::new();
-                hcx.while_hashing_spans(false, |hcx| ct.val().hash_stable(hcx, &mut hasher));
+                let ct = ct.eval(tcx, ty::ParamEnv::reveal_all());
+                hcx.while_hashing_spans(false, |hcx| ct.to_valtree().hash_stable(hcx, &mut hasher));
                 // Let's only emit 64 bits of the hash value. That should be plenty for
                 // avoiding collisions and will make the emitted type names shorter.
-                let hash: u64 = hasher.finish();
+                // Note: Don't use `StableHashResult` impl of `u64` here directly, since that
+                // would lead to endianness problems.
+                let hash: u128 = hasher.finish();
+                let hash_short = (hash.to_le() as u64).to_le();
 
                 if cpp_like_debuginfo(tcx) {
-                    write!(output, "CONST${:x}", hash)
+                    write!(output, "CONST${:x}", hash_short)
                 } else {
-                    write!(output, "{{CONST#{:x}}}", hash)
+                    write!(output, "{{CONST#{:x}}}", hash_short)
                 }
             }
         },
diff --git a/compiler/rustc_codegen_ssa/src/glue.rs b/compiler/rustc_codegen_ssa/src/glue.rs
index 694f543..e6f402e 100644
--- a/compiler/rustc_codegen_ssa/src/glue.rs
+++ b/compiler/rustc_codegen_ssa/src/glue.rs
@@ -39,7 +39,12 @@
             // The info in this case is the length of the str, so the size is that
             // times the unit size.
             (
-                bx.mul(info.unwrap(), bx.const_usize(unit.size.bytes())),
+                // All slice sizes must fit into `isize`, so this multiplication cannot (signed) wrap.
+                // NOTE: ideally, we want the effects of both `unchecked_smul` and `unchecked_umul`
+                // (resulting in `mul nsw nuw` in LLVM IR), since we know that the multiplication
+                // cannot signed wrap, and that both operands are non-negative. But at the time of writing,
+                // `BuilderMethods` can't do this, and it doesn't seem to enable any further optimizations.
+                bx.unchecked_smul(info.unwrap(), bx.const_usize(unit.size.bytes())),
                 bx.const_usize(unit.align.abi.bytes()),
             )
         }
diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs
index 9e1fe58..6c30923 100644
--- a/compiler/rustc_codegen_ssa/src/lib.rs
+++ b/compiler/rustc_codegen_ssa/src/lib.rs
@@ -3,7 +3,6 @@
 #![feature(try_blocks)]
 #![feature(let_else)]
 #![feature(once_cell)]
-#![feature(nll)]
 #![feature(associated_type_bounds)]
 #![feature(strict_provenance)]
 #![feature(int_roundings)]
@@ -30,12 +29,14 @@
 use rustc_middle::middle::dependency_format::Dependencies;
 use rustc_middle::middle::exported_symbols::SymbolExportKind;
 use rustc_middle::ty::query::{ExternProviders, Providers};
-use rustc_serialize::{opaque, Decodable, Decoder, Encoder};
+use rustc_serialize::opaque::{MemDecoder, MemEncoder};
+use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
 use rustc_session::config::{CrateType, OutputFilenames, OutputType, RUST_CGU_EXT};
 use rustc_session::cstore::{self, CrateSource};
 use rustc_session::utils::NativeLibKind;
 use rustc_span::symbol::Symbol;
 use rustc_span::DebuggerVisualizerFile;
+use std::collections::BTreeSet;
 use std::path::{Path, PathBuf};
 
 pub mod back;
@@ -157,7 +158,7 @@
     pub missing_lang_items: FxHashMap<CrateNum, Vec<LangItem>>,
     pub dependency_formats: Lrc<Dependencies>,
     pub windows_subsystem: Option<String>,
-    pub debugger_visualizers: FxHashMap<CrateNum, Vec<DebuggerVisualizerFile>>,
+    pub natvis_debugger_visualizers: BTreeSet<DebuggerVisualizerFile>,
 }
 
 #[derive(Encodable, Decodable)]
@@ -203,16 +204,14 @@
 
 impl CodegenResults {
     pub fn serialize_rlink(codegen_results: &CodegenResults) -> Vec<u8> {
-        let mut encoder = opaque::Encoder::new(vec![]);
-        encoder.emit_raw_bytes(RLINK_MAGIC).unwrap();
+        let mut encoder = MemEncoder::new();
+        encoder.emit_raw_bytes(RLINK_MAGIC);
         // `emit_raw_bytes` is used to make sure that the version representation does not depend on
         // Encoder's inner representation of `u32`.
-        encoder.emit_raw_bytes(&RLINK_VERSION.to_be_bytes()).unwrap();
-        encoder.emit_str(RUSTC_VERSION.unwrap()).unwrap();
-
-        let mut encoder = rustc_serialize::opaque::Encoder::new(encoder.into_inner());
-        rustc_serialize::Encodable::encode(codegen_results, &mut encoder).unwrap();
-        encoder.into_inner()
+        encoder.emit_raw_bytes(&RLINK_VERSION.to_be_bytes());
+        encoder.emit_str(RUSTC_VERSION.unwrap());
+        Encodable::encode(codegen_results, &mut encoder);
+        encoder.finish()
     }
 
     pub fn deserialize_rlink(data: Vec<u8>) -> Result<Self, String> {
@@ -232,7 +231,7 @@
             return Err(".rlink file was produced with encoding version {version_array}, but the current version is {RLINK_VERSION}".to_string());
         }
 
-        let mut decoder = opaque::Decoder::new(&data[4..], 0);
+        let mut decoder = MemDecoder::new(&data[4..], 0);
         let rustc_version = decoder.read_str();
         let current_version = RUSTC_VERSION.unwrap();
         if rustc_version != current_version {
diff --git a/compiler/rustc_codegen_ssa/src/meth.rs b/compiler/rustc_codegen_ssa/src/meth.rs
index 00f1015..5203ebf 100644
--- a/compiler/rustc_codegen_ssa/src/meth.rs
+++ b/compiler/rustc_codegen_ssa/src/meth.rs
@@ -1,6 +1,8 @@
 use crate::traits::*;
 
-use rustc_middle::ty::{self, Ty};
+use rustc_middle::ty::{self, subst::GenericArgKind, ExistentialPredicate, Ty, TyCtxt};
+use rustc_session::config::Lto;
+use rustc_symbol_mangling::typeid_for_trait_ref;
 use rustc_target::abi::call::FnAbi;
 
 #[derive(Copy, Clone, Debug)]
@@ -15,20 +17,32 @@
         self,
         bx: &mut Bx,
         llvtable: Bx::Value,
+        ty: Ty<'tcx>,
         fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
     ) -> Bx::Value {
         // Load the data pointer from the object.
-        debug!("get_fn({:?}, {:?})", llvtable, self);
-
+        debug!("get_fn({llvtable:?}, {ty:?}, {self:?})");
         let llty = bx.fn_ptr_backend_type(fn_abi);
         let llvtable = bx.pointercast(llvtable, bx.type_ptr_to(llty));
-        let ptr_align = bx.tcx().data_layout.pointer_align.abi;
-        let gep = bx.inbounds_gep(llty, llvtable, &[bx.const_usize(self.0)]);
-        let ptr = bx.load(llty, gep, ptr_align);
-        bx.nonnull_metadata(ptr);
-        // Vtable loads are invariant.
-        bx.set_invariant_load(ptr);
-        ptr
+
+        if bx.cx().sess().opts.debugging_opts.virtual_function_elimination
+            && bx.cx().sess().lto() == Lto::Fat
+        {
+            let typeid =
+                bx.typeid_metadata(typeid_for_trait_ref(bx.tcx(), get_trait_ref(bx.tcx(), ty)));
+            let vtable_byte_offset = self.0 * bx.data_layout().pointer_size.bytes();
+            let type_checked_load = bx.type_checked_load(llvtable, vtable_byte_offset, typeid);
+            let func = bx.extract_value(type_checked_load, 0);
+            bx.pointercast(func, llty)
+        } else {
+            let ptr_align = bx.tcx().data_layout.pointer_align.abi;
+            let gep = bx.inbounds_gep(llty, llvtable, &[bx.const_usize(self.0)]);
+            let ptr = bx.load(llty, gep, ptr_align);
+            bx.nonnull_metadata(ptr);
+            // Vtable loads are invariant.
+            bx.set_invariant_load(ptr);
+            ptr
+        }
     }
 
     pub fn get_usize<Bx: BuilderMethods<'a, 'tcx>>(
@@ -50,6 +64,24 @@
     }
 }
 
+fn get_trait_ref<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> ty::PolyExistentialTraitRef<'tcx> {
+    for arg in ty.peel_refs().walk() {
+        if let GenericArgKind::Type(ty) = arg.unpack() {
+            if let ty::Dynamic(trait_refs, _) = ty.kind() {
+                return trait_refs[0].map_bound(|trait_ref| match trait_ref {
+                    ExistentialPredicate::Trait(tr) => tr,
+                    ExistentialPredicate::Projection(proj) => proj.trait_ref(tcx),
+                    ExistentialPredicate::AutoTrait(_) => {
+                        bug!("auto traits don't have functions")
+                    }
+                });
+            }
+        }
+    }
+
+    bug!("expected a `dyn Trait` ty, found {ty:?}")
+}
+
 /// Creates a dynamic vtable for the given type and vtable origin.
 /// This is used only for objects.
 ///
diff --git a/compiler/rustc_codegen_ssa/src/mir/analyze.rs b/compiler/rustc_codegen_ssa/src/mir/analyze.rs
index fa39e8d..80dab11 100644
--- a/compiler/rustc_codegen_ssa/src/mir/analyze.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/analyze.rs
@@ -328,7 +328,7 @@
                 bb, data, result[bb], funclet
             );
 
-            for &succ in data.terminator().successors() {
+            for succ in data.terminator().successors() {
                 let kind = result[succ];
                 debug!("cleanup_kinds: propagating {:?} to {:?}/{:?}", funclet, succ, kind);
                 match kind {
diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index a185eb2..db348f2 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -22,7 +22,7 @@
 use rustc_span::{sym, Symbol};
 use rustc_symbol_mangling::typeid_for_fnabi;
 use rustc_target::abi::call::{ArgAbi, FnAbi, PassMode};
-use rustc_target::abi::{self, HasDataLayout, WrappingRange};
+use rustc_target::abi::{self, HasDataLayout, InitKind, WrappingRange};
 use rustc_target::spec::abi::Abi;
 
 /// Used by `FunctionCx::codegen_terminator` for emitting common patterns
@@ -401,7 +401,7 @@
                 args = &args[..1];
                 (
                     meth::VirtualIndex::from_index(ty::COMMON_VTABLE_ENTRIES_DROPINPLACE)
-                        .get_fn(&mut bx, vtable, &fn_abi),
+                        .get_fn(&mut bx, vtable, ty, &fn_abi),
                     fn_abi,
                 )
             }
@@ -519,8 +519,9 @@
         intrinsic: Option<Symbol>,
         instance: Option<Instance<'tcx>>,
         source_info: mir::SourceInfo,
-        destination: &Option<(mir::Place<'tcx>, mir::BasicBlock)>,
+        target: Option<mir::BasicBlock>,
         cleanup: Option<mir::BasicBlock>,
+        strict_validity: bool,
     ) -> bool {
         // Emit a panic or a no-op for `assert_*` intrinsics.
         // These are intrinsics that compile to panics so that we can get a message
@@ -543,8 +544,8 @@
             let layout = bx.layout_of(ty);
             let do_panic = match intrinsic {
                 Inhabited => layout.abi.is_uninhabited(),
-                ZeroValid => !layout.might_permit_raw_init(bx, /*zero:*/ true),
-                UninitValid => !layout.might_permit_raw_init(bx, /*zero:*/ false),
+                ZeroValid => !layout.might_permit_raw_init(bx, InitKind::Zero, strict_validity),
+                UninitValid => !layout.might_permit_raw_init(bx, InitKind::Uninit, strict_validity),
             };
             if do_panic {
                 let msg_str = with_no_visible_paths!({
@@ -576,12 +577,12 @@
                     fn_abi,
                     llfn,
                     &[msg.0, msg.1, location],
-                    destination.as_ref().map(|(_, bb)| (ReturnDest::Nothing, *bb)),
+                    target.as_ref().map(|bb| (ReturnDest::Nothing, *bb)),
                     cleanup,
                 );
             } else {
                 // a NOP
-                let target = destination.as_ref().unwrap().1;
+                let target = target.unwrap();
                 helper.funclet_br(self, bx, target)
             }
             true
@@ -597,7 +598,8 @@
         terminator: &mir::Terminator<'tcx>,
         func: &mir::Operand<'tcx>,
         args: &[mir::Operand<'tcx>],
-        destination: &Option<(mir::Place<'tcx>, mir::BasicBlock)>,
+        destination: mir::Place<'tcx>,
+        target: Option<mir::BasicBlock>,
         cleanup: Option<mir::BasicBlock>,
         fn_span: Span,
     ) {
@@ -624,7 +626,7 @@
 
         if let Some(ty::InstanceDef::DropGlue(_, None)) = def {
             // Empty drop glue; a no-op.
-            let &(_, target) = destination.as_ref().unwrap();
+            let target = target.unwrap();
             helper.funclet_br(self, &mut bx, target);
             return;
         }
@@ -653,9 +655,8 @@
         };
 
         if intrinsic == Some(sym::transmute) {
-            if let Some(destination_ref) = destination.as_ref() {
-                let &(dest, target) = destination_ref;
-                self.codegen_transmute(&mut bx, &args[0], dest);
+            if let Some(target) = target {
+                self.codegen_transmute(&mut bx, &args[0], destination);
                 helper.funclet_br(self, &mut bx, target);
             } else {
                 // If we are trying to transmute to an uninhabited type,
@@ -676,8 +677,9 @@
             intrinsic,
             instance,
             source_info,
-            destination,
+            target,
             cleanup,
+            self.cx.tcx().sess.opts.debugging_opts.strict_init_checks,
         ) {
             return;
         }
@@ -687,15 +689,15 @@
         let mut llargs = Vec::with_capacity(arg_count);
 
         // Prepare the return value destination
-        let ret_dest = if let Some((dest, _)) = *destination {
+        let ret_dest = if target.is_some() {
             let is_intrinsic = intrinsic.is_some();
-            self.make_return_dest(&mut bx, dest, &fn_abi.ret, &mut llargs, is_intrinsic)
+            self.make_return_dest(&mut bx, destination, &fn_abi.ret, &mut llargs, is_intrinsic)
         } else {
             ReturnDest::Nothing
         };
 
         if intrinsic == Some(sym::caller_location) {
-            if let Some((_, target)) = destination.as_ref() {
+            if let Some(target) = target {
                 let location = self
                     .get_caller_location(&mut bx, mir::SourceInfo { span: fn_span, ..source_info });
 
@@ -703,7 +705,7 @@
                     location.val.store(&mut bx, tmp);
                 }
                 self.store_return(&mut bx, ret_dest, &fn_abi.ret, location.immediate());
-                helper.funclet_br(self, &mut bx, *target);
+                helper.funclet_br(self, &mut bx, target);
             }
             return;
         }
@@ -766,7 +768,7 @@
                     self.store_return(&mut bx, ret_dest, &fn_abi.ret, dst.llval);
                 }
 
-                if let Some((_, target)) = *destination {
+                if let Some(target) = target {
                     helper.funclet_br(self, &mut bx, target);
                 } else {
                     bx.unreachable();
@@ -817,9 +819,12 @@
                     // the data pointer as the first argument
                     match op.val {
                         Pair(data_ptr, meta) => {
-                            llfn = Some(
-                                meth::VirtualIndex::from_index(idx).get_fn(&mut bx, meta, &fn_abi),
-                            );
+                            llfn = Some(meth::VirtualIndex::from_index(idx).get_fn(
+                                &mut bx,
+                                meta,
+                                op.layout.ty,
+                                &fn_abi,
+                            ));
                             llargs.push(data_ptr);
                             continue 'make_args;
                         }
@@ -827,7 +832,12 @@
                     }
                 } else if let Ref(data_ptr, Some(meta), _) = op.val {
                     // by-value dynamic dispatch
-                    llfn = Some(meth::VirtualIndex::from_index(idx).get_fn(&mut bx, meta, &fn_abi));
+                    llfn = Some(meth::VirtualIndex::from_index(idx).get_fn(
+                        &mut bx,
+                        meta,
+                        op.layout.ty,
+                        &fn_abi,
+                    ));
                     llargs.push(data_ptr);
                     continue;
                 } else {
@@ -913,7 +923,7 @@
                 fn_abi,
                 fn_ptr,
                 &llargs,
-                destination.as_ref().map(|&(_, target)| (ret_dest, target)),
+                target.as_ref().map(|&target| (ret_dest, target)),
                 cleanup,
             );
 
@@ -930,7 +940,7 @@
             fn_abi,
             fn_ptr,
             &llargs,
-            destination.as_ref().map(|&(_, target)| (ret_dest, target)),
+            target.as_ref().map(|&target| (ret_dest, target)),
             cleanup,
         );
     }
@@ -1083,7 +1093,8 @@
             mir::TerminatorKind::Call {
                 ref func,
                 ref args,
-                ref destination,
+                destination,
+                target,
                 cleanup,
                 from_hir_call: _,
                 fn_span,
@@ -1095,6 +1106,7 @@
                     func,
                     args,
                     destination,
+                    target,
                     cleanup,
                     fn_span,
                 );
diff --git a/compiler/rustc_codegen_ssa/src/mir/constant.rs b/compiler/rustc_codegen_ssa/src/mir/constant.rs
index 479b2b05..9a995fb 100644
--- a/compiler/rustc_codegen_ssa/src/mir/constant.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/constant.rs
@@ -29,7 +29,7 @@
             mir::ConstantKind::Ty(ct) => ct,
             mir::ConstantKind::Val(val, _) => return Ok(val),
         };
-        match ct.val() {
+        match ct.kind() {
             ty::ConstKind::Unevaluated(ct) => self
                 .cx
                 .tcx()
@@ -38,7 +38,7 @@
                     self.cx.tcx().sess.span_err(constant.span, "erroneous constant encountered");
                     err
                 }),
-            ty::ConstKind::Value(value) => Ok(value),
+            ty::ConstKind::Value(val) => Ok(self.cx.tcx().valtree_to_const_val((ct.ty(), val))),
             err => span_bug!(
                 constant.span,
                 "encountered bad ConstKind after monomorphizing: {:?}",
@@ -58,14 +58,14 @@
         constant
             .map(|val| {
                 let field_ty = ty.builtin_index().unwrap();
-                let c = ty::Const::from_value(bx.tcx(), val, ty);
+                let c = mir::ConstantKind::from_value(val, ty);
                 let values: Vec<_> = bx
                     .tcx()
-                    .destructure_const(ty::ParamEnv::reveal_all().and(c))
+                    .destructure_mir_constant(ty::ParamEnv::reveal_all(), c)
                     .fields
                     .iter()
                     .map(|field| {
-                        if let Some(prim) = field.val().try_to_scalar() {
+                        if let Some(prim) = field.try_to_scalar() {
                             let layout = bx.layout_of(field_ty);
                             let Abi::Scalar(scalar) = layout.abi else {
                                 bug!("from_const: invalid ByVal layout: {:#?}", layout);
diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
index 6d6d3ae..0ed4c3f 100644
--- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
@@ -388,17 +388,17 @@
                     2 => (SequentiallyConsistent, SequentiallyConsistent),
                     3 => match split[2] {
                         "unordered" => (Unordered, Unordered),
-                        "relaxed" => (Monotonic, Monotonic),
+                        "relaxed" => (Relaxed, Relaxed),
                         "acq" => (Acquire, Acquire),
-                        "rel" => (Release, Monotonic),
+                        "rel" => (Release, Relaxed),
                         "acqrel" => (AcquireRelease, Acquire),
-                        "failrelaxed" if is_cxchg => (SequentiallyConsistent, Monotonic),
+                        "failrelaxed" if is_cxchg => (SequentiallyConsistent, Relaxed),
                         "failacq" if is_cxchg => (SequentiallyConsistent, Acquire),
                         _ => bx.sess().fatal("unknown ordering in atomic intrinsic"),
                     },
                     4 => match (split[2], split[3]) {
-                        ("acq", "failrelaxed") if is_cxchg => (Acquire, Monotonic),
-                        ("acqrel", "failrelaxed") if is_cxchg => (AcquireRelease, Monotonic),
+                        ("acq", "failrelaxed") if is_cxchg => (Acquire, Relaxed),
+                        ("acqrel", "failrelaxed") if is_cxchg => (AcquireRelease, Relaxed),
                         _ => bx.sess().fatal("unknown ordering in atomic intrinsic"),
                     },
                     _ => bx.sess().fatal("Atomic intrinsic not in correct format"),
diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs
index 08be4c0..2e655ae 100644
--- a/compiler/rustc_codegen_ssa/src/mir/operand.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs
@@ -118,22 +118,20 @@
     }
 
     pub fn deref<Cx: LayoutTypeMethods<'tcx>>(self, cx: &Cx) -> PlaceRef<'tcx, V> {
+        if self.layout.ty.is_box() {
+            bug!("dereferencing {:?} in codegen", self.layout.ty);
+        }
+
         let projected_ty = self
             .layout
             .ty
             .builtin_deref(true)
             .unwrap_or_else(|| bug!("deref of non-pointer {:?}", self))
             .ty;
+
         let (llptr, llextra) = match self.val {
             OperandValue::Immediate(llptr) => (llptr, None),
-            OperandValue::Pair(llptr, llextra) => {
-                // if the box's allocator isn't a ZST, then "llextra" is actually the allocator
-                if self.layout.ty.is_box() && !self.layout.field(cx, 1).is_zst() {
-                    (llptr, None)
-                } else {
-                    (llptr, Some(llextra))
-                }
-            }
+            OperandValue::Pair(llptr, llextra) => (llptr, Some(llextra)),
             OperandValue::Ref(..) => bug!("Deref of by-Ref operand {:?}", self),
         };
         let layout = cx.layout_of(projected_ty);
diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs
index b6a7bca..5b88635 100644
--- a/compiler/rustc_codegen_ssa/src/mir/place.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/place.rs
@@ -446,35 +446,15 @@
                         mir::PlaceRef { projection: &place_ref.projection[..elem.0], ..place_ref },
                     );
 
-                    // a box with a non-zst allocator should not be directly dereferenced
-                    if cg_base.layout.ty.is_box() && !cg_base.layout.field(cx, 1).is_zst() {
-                        // Extract `Box<T>` -> `Unique<T>` -> `NonNull<T>` -> `*const T`
-                        let ptr =
-                            cg_base.extract_field(bx, 0).extract_field(bx, 0).extract_field(bx, 0);
-
-                        ptr.deref(bx.cx())
-                    } else {
-                        cg_base.deref(bx.cx())
-                    }
+                    cg_base.deref(bx.cx())
                 } else {
                     bug!("using operand local {:?} as place", place_ref);
                 }
             }
         };
         for elem in place_ref.projection[base..].iter() {
-            cg_base = match elem.clone() {
-                mir::ProjectionElem::Deref => {
-                    // a box with a non-zst allocator should not be directly dereferenced
-                    if cg_base.layout.ty.is_box() && !cg_base.layout.field(cx, 1).is_zst() {
-                        // Project `Box<T>` -> `Unique<T>` -> `NonNull<T>` -> `*const T`
-                        let ptr =
-                            cg_base.project_field(bx, 0).project_field(bx, 0).project_field(bx, 0);
-
-                        bx.load_operand(ptr).deref(bx.cx())
-                    } else {
-                        bx.load_operand(cg_base).deref(bx.cx())
-                    }
-                }
+            cg_base = match *elem {
+                mir::ProjectionElem::Deref => bx.load_operand(cg_base).deref(bx.cx()),
                 mir::ProjectionElem::Field(ref field, _) => {
                     cg_base.project_field(bx, field.index())
                 }
diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
index fd29c9e..81c1897 100644
--- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
@@ -181,6 +181,13 @@
                 let cast = bx.cx().layout_of(self.monomorphize(mir_cast_ty));
 
                 let val = match *kind {
+                    mir::CastKind::PointerExposeAddress => {
+                        assert!(bx.cx().is_backend_immediate(cast));
+                        let llptr = operand.immediate();
+                        let llcast_ty = bx.cx().immediate_backend_type(cast);
+                        let lladdr = bx.ptrtoint(llptr, llcast_ty);
+                        OperandValue::Immediate(lladdr)
+                    }
                     mir::CastKind::Pointer(PointerCast::ReifyFnPointer) => {
                         match *operand.layout.ty.kind() {
                             ty::FnDef(def_id, substs) => {
@@ -262,7 +269,11 @@
                     mir::CastKind::Pointer(
                         PointerCast::MutToConstPointer | PointerCast::ArrayToPointer,
                     )
-                    | mir::CastKind::Misc => {
+                    | mir::CastKind::Misc
+                    // Since int2ptr can have arbitrary integer types as input (so we have to do
+                    // sign extension and all that), it is currently best handled in the same code
+                    // path as the other integer-to-X casts.
+                    | mir::CastKind::PointerFromExposedAddress => {
                         assert!(bx.cx().is_backend_immediate(cast));
                         let ll_t_out = bx.cx().immediate_backend_type(cast);
                         if operand.layout.abi.is_uninhabited() {
@@ -362,9 +373,6 @@
                             (CastTy::Ptr(_) | CastTy::FnPtr, CastTy::Ptr(_)) => {
                                 bx.pointercast(llval, ll_t_out)
                             }
-                            (CastTy::Ptr(_) | CastTy::FnPtr, CastTy::Int(_)) => {
-                                bx.ptrtoint(llval, ll_t_out)
-                            }
                             (CastTy::Int(_), CastTy::Ptr(_)) => {
                                 let usize_llval = bx.intcast(llval, bx.cx().type_isize(), signed);
                                 bx.inttoptr(usize_llval, ll_t_out)
diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs
index ba1e186..bfdef2d 100644
--- a/compiler/rustc_codegen_ssa/src/target_features.rs
+++ b/compiler/rustc_codegen_ssa/src/target_features.rs
@@ -246,6 +246,9 @@
     ("simd128", None),
     ("atomics", Some(sym::wasm_target_feature)),
     ("nontrapping-fptoint", Some(sym::wasm_target_feature)),
+    ("bulk-memory", Some(sym::wasm_target_feature)),
+    ("mutable-globals", Some(sym::wasm_target_feature)),
+    ("reference-types", Some(sym::wasm_target_feature)),
 ];
 
 const BPF_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[("alu32", Some(sym::bpf_target_feature))];
diff --git a/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs b/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs
index 02be6cd..7755e67 100644
--- a/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs
@@ -22,6 +22,14 @@
     fn expect(&mut self, cond: Self::Value, expected: bool) -> Self::Value;
     /// Trait method used to test whether a given pointer is associated with a type identifier.
     fn type_test(&mut self, pointer: Self::Value, typeid: Self::Value) -> Self::Value;
+    /// Trait method used to load a function while testing if it is associated with a type
+    /// identifier.
+    fn type_checked_load(
+        &mut self,
+        llvtable: Self::Value,
+        vtable_byte_offset: u64,
+        typeid: Self::Value,
+    ) -> Self::Value;
     /// Trait method used to inject `va_start` on the "spoofed" `VaListImpl` in
     /// Rust defined C-variadic functions.
     fn va_start(&mut self, val: Self::Value) -> Self::Value;
diff --git a/compiler/rustc_const_eval/Cargo.toml b/compiler/rustc_const_eval/Cargo.toml
index 4ed908a..32e8233 100644
--- a/compiler/rustc_const_eval/Cargo.toml
+++ b/compiler/rustc_const_eval/Cargo.toml
@@ -24,3 +24,4 @@
 rustc_target = { path = "../rustc_target" }
 rustc_trait_selection = { path = "../rustc_trait_selection" }
 rustc_span = { path = "../rustc_span" }
+rustc_type_ir = { path = "../rustc_type_ir" }
diff --git a/compiler/rustc_const_eval/src/const_eval/error.rs b/compiler/rustc_const_eval/src/const_eval/error.rs
index 3bd0922..3eeb013 100644
--- a/compiler/rustc_const_eval/src/const_eval/error.rs
+++ b/compiler/rustc_const_eval/src/const_eval/error.rs
@@ -140,6 +140,7 @@
     ///
     /// If `lint_root.is_some()` report it as a lint, else report it as a hard error.
     /// (Except that for some errors, we ignore all that -- see `must_error` below.)
+    #[instrument(skip(self, tcx, decorate, lint_root), level = "debug")]
     fn struct_generic(
         &self,
         tcx: TyCtxtAt<'tcx>,
@@ -190,6 +191,7 @@
             decorate(err);
         };
 
+        debug!("self.error: {:?}", self.error);
         // Special handling for certain errors
         match &self.error {
             // Don't emit a new diagnostic for these errors
diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
index 5c56e6e..b7e5e7a 100644
--- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
+++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
@@ -60,7 +60,7 @@
     ecx.push_stack_frame(
         cid.instance,
         body,
-        Some(&ret.into()),
+        &ret.into(),
         StackPopCleanup::Root { cleanup: false },
     )?;
 
@@ -135,7 +135,7 @@
     } else {
         // It is guaranteed that any non-slice scalar pair is actually ByRef here.
         // When we come back from raw const eval, we are always by-ref. The only way our op here is
-        // by-val is if we are in destructure_const, i.e., if this is (a field of) something that we
+        // by-val is if we are in destructure_mir_constant, i.e., if this is (a field of) something that we
         // "tried to make immediate" before. We wouldn't do that for non-slice scalar pairs or
         // structs containing such.
         op.try_as_mplace()
@@ -196,7 +196,7 @@
 }
 
 #[instrument(skip(tcx), level = "debug")]
-fn turn_into_const_value<'tcx>(
+pub(crate) fn turn_into_const_value<'tcx>(
     tcx: TyCtxt<'tcx>,
     constant: ConstAlloc<'tcx>,
     key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>,
@@ -222,6 +222,7 @@
     const_val
 }
 
+#[instrument(skip(tcx), level = "debug")]
 pub fn eval_to_const_value_raw_provider<'tcx>(
     tcx: TyCtxt<'tcx>,
     key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>,
@@ -256,6 +257,7 @@
     tcx.eval_to_allocation_raw(key).map(|val| turn_into_const_value(tcx, val, key))
 }
 
+#[instrument(skip(tcx), level = "debug")]
 pub fn eval_to_allocation_raw_provider<'tcx>(
     tcx: TyCtxt<'tcx>,
     key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>,
diff --git a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs
index 1f291db..f1674d0 100644
--- a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs
+++ b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs
@@ -4,13 +4,12 @@
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::{DefIdTree, TyCtxt};
 use rustc_span::symbol::Symbol;
-use rustc_target::spec::abi::Abi;
 
 /// Whether the `def_id` is an unstable const fn and what feature gate is necessary to enable it
 pub fn is_unstable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Symbol> {
     if tcx.is_const_fn_raw(def_id) {
         let const_stab = tcx.lookup_const_stability(def_id)?;
-        if const_stab.level.is_unstable() { Some(const_stab.feature) } else { None }
+        if const_stab.is_const_unstable() { Some(const_stab.feature) } else { None }
     } else {
         None
     }
@@ -18,13 +17,14 @@
 
 pub fn is_parent_const_impl_raw(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
     let parent_id = tcx.local_parent(def_id);
-    tcx.def_kind(parent_id) == DefKind::Impl
-        && tcx.impl_constness(parent_id) == hir::Constness::Const
+    tcx.def_kind(parent_id) == DefKind::Impl && tcx.constness(parent_id) == hir::Constness::Const
 }
 
-/// Checks whether the function has a `const` modifier or, in case it is an intrinsic, whether
-/// said intrinsic has a `rustc_const_{un,}stable` attribute.
-fn impl_constness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::Constness {
+/// Checks whether an item is considered to be `const`. If it is a constructor, it is const. If
+/// it is a trait impl/function, return if it has a `const` modifier. If it is an intrinsic,
+/// report whether said intrinsic has a `rustc_const_{un,}stable` attribute. Otherwise, return
+/// `Constness::NotConst`.
+fn constness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::Constness {
     let def_id = def_id.expect_local();
     let node = tcx.hir().get_by_def_id(def_id);
 
@@ -34,10 +34,7 @@
         hir::Node::ForeignItem(hir::ForeignItem { kind: hir::ForeignItemKind::Fn(..), .. }) => {
             // Intrinsics use `rustc_const_{un,}stable` attributes to indicate constness. All other
             // foreign items cannot be evaluated at compile-time.
-            let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
-            let is_const = if let Abi::RustIntrinsic | Abi::PlatformIntrinsic =
-                tcx.hir().get_foreign_abi(hir_id)
-            {
+            let is_const = if tcx.is_intrinsic(def_id) {
                 tcx.lookup_const_stability(def_id).is_some()
             } else {
                 false
@@ -81,5 +78,5 @@
 }
 
 pub fn provide(providers: &mut Providers) {
-    *providers = Providers { impl_constness, is_promotable_const_fn, ..*providers };
+    *providers = Providers { constness, is_promotable_const_fn, ..*providers };
 }
diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs
index c5a11aa..ac529bf 100644
--- a/compiler/rustc_const_eval/src/const_eval/machine.rs
+++ b/compiler/rustc_const_eval/src/const_eval/machine.rs
@@ -163,7 +163,7 @@
     }
 }
 
-crate type CompileTimeEvalContext<'mir, 'tcx> =
+pub(crate) type CompileTimeEvalContext<'mir, 'tcx> =
     InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>>;
 
 #[derive(Debug, PartialEq, Eq, Copy, Clone)]
@@ -265,7 +265,8 @@
         instance: ty::Instance<'tcx>,
         _abi: Abi,
         args: &[OpTy<'tcx>],
-        _ret: Option<(&PlaceTy<'tcx>, mir::BasicBlock)>,
+        _dest: &PlaceTy<'tcx>,
+        _ret: Option<mir::BasicBlock>,
         _unwind: StackPopUnwind, // unwinding is not supported in consts
     ) -> InterpResult<'tcx, Option<(&'mir mir::Body<'tcx>, ty::Instance<'tcx>)>> {
         debug!("find_mir_or_eval_fn: {:?}", instance);
@@ -276,8 +277,8 @@
             // sensitive check here.  But we can at least rule out functions that are not const
             // at all.
             if !ecx.tcx.is_const_fn_raw(def.did) {
-                // allow calling functions marked with #[default_method_body_is_const].
-                if !ecx.tcx.has_attr(def.did, sym::default_method_body_is_const) {
+                // allow calling functions inside a trait marked with #[const_trait].
+                if !ecx.tcx.is_const_default_method(def.did) {
                     // We certainly do *not* want to actually call the fn
                     // though, so be sure we return here.
                     throw_unsup_format!("calling non-const function `{}`", instance)
@@ -293,6 +294,7 @@
                     new_instance,
                     _abi,
                     args,
+                    _dest,
                     _ret,
                     _unwind,
                 )?
@@ -307,17 +309,18 @@
         ecx: &mut InterpCx<'mir, 'tcx, Self>,
         instance: ty::Instance<'tcx>,
         args: &[OpTy<'tcx>],
-        ret: Option<(&PlaceTy<'tcx>, mir::BasicBlock)>,
+        dest: &PlaceTy<'tcx, Self::PointerTag>,
+        target: Option<mir::BasicBlock>,
         _unwind: StackPopUnwind,
     ) -> InterpResult<'tcx> {
         // Shared intrinsics.
-        if ecx.emulate_intrinsic(instance, args, ret)? {
+        if ecx.emulate_intrinsic(instance, args, dest, target)? {
             return Ok(());
         }
         let intrinsic_name = ecx.tcx.item_name(instance.def_id());
 
         // CTFE-specific intrinsics.
-        let Some((dest, ret)) = ret else {
+        let Some(ret) = target else {
             return Err(ConstEvalErrKind::NeedsRfc(format!(
                 "calling intrinsic `{}`",
                 intrinsic_name
diff --git a/compiler/rustc_const_eval/src/const_eval/mod.rs b/compiler/rustc_const_eval/src/const_eval/mod.rs
index 96c18d4..a1d2e5c 100644
--- a/compiler/rustc_const_eval/src/const_eval/mod.rs
+++ b/compiler/rustc_const_eval/src/const_eval/mod.rs
@@ -1,11 +1,11 @@
 // Not in interpret to make sure we do not use private implementation details
 
-use std::convert::TryFrom;
-
 use rustc_hir::Mutability;
 use rustc_middle::mir;
+use rustc_middle::mir::interpret::{EvalToValTreeResult, GlobalId};
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_span::{source_map::DUMMY_SP, symbol::Symbol};
+use rustc_target::abi::VariantIdx;
 
 use crate::interpret::{
     intern_const_alloc_recursive, ConstValue, InternKind, InterpCx, InterpResult, MemPlaceMeta,
@@ -22,7 +22,7 @@
 pub use eval_queries::*;
 pub use fn_queries::*;
 pub use machine::*;
-pub(crate) use valtrees::{const_to_valtree, valtree_to_const_value};
+pub(crate) use valtrees::{const_to_valtree_inner, valtree_to_const_value};
 
 pub(crate) fn const_caller_location(
     tcx: TyCtxt<'_>,
@@ -38,67 +38,194 @@
     ConstValue::Scalar(Scalar::from_maybe_pointer(loc_place.ptr, &tcx))
 }
 
-/// This function should never fail for validated constants. However, it is also invoked from the
-/// pretty printer which might attempt to format invalid constants and in that case it might fail.
-pub(crate) fn try_destructure_const<'tcx>(
+// We forbid type-level constants that contain more than `VALTREE_MAX_NODES` nodes.
+const VALTREE_MAX_NODES: usize = 100000;
+
+pub(crate) enum ValTreeCreationError {
+    NodesOverflow,
+    NonSupportedType,
+    Other,
+}
+pub(crate) type ValTreeCreationResult<'tcx> = Result<ty::ValTree<'tcx>, ValTreeCreationError>;
+
+/// Evaluates a constant and turns it into a type-level constant value.
+pub(crate) fn eval_to_valtree<'tcx>(
     tcx: TyCtxt<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
-    val: ty::Const<'tcx>,
-) -> InterpResult<'tcx, mir::DestructuredConst<'tcx>> {
-    trace!("destructure_const: {:?}", val);
-    let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, false);
-    let op = ecx.const_to_op(val, None)?;
+    cid: GlobalId<'tcx>,
+) -> EvalToValTreeResult<'tcx> {
+    let const_alloc = tcx.eval_to_allocation_raw(param_env.and(cid))?;
 
-    // We go to `usize` as we cannot allocate anything bigger anyway.
-    let (field_count, variant, down) = match val.ty().kind() {
-        ty::Array(_, len) => (usize::try_from(len.eval_usize(tcx, param_env)).unwrap(), None, op),
-        // Checks if we have any variants, to avoid downcasting to a non-existing variant (when
-        // there are no variants `read_discriminant` successfully returns a non-existing variant
-        // index).
-        ty::Adt(def, _) if def.variants().is_empty() => throw_ub!(Unreachable),
-        ty::Adt(def, _) => {
-            let variant = ecx.read_discriminant(&op)?.1;
-            let down = ecx.operand_downcast(&op, variant)?;
-            (def.variant(variant).fields.len(), Some(variant), down)
+    // FIXME Need to provide a span to `eval_to_valtree`
+    let ecx = mk_eval_cx(
+        tcx, DUMMY_SP, param_env,
+        // It is absolutely crucial for soundness that
+        // we do not read from static items or other mutable memory.
+        false,
+    );
+    let place = ecx.raw_const_to_mplace(const_alloc).unwrap();
+    debug!(?place);
+
+    let mut num_nodes = 0;
+    let valtree_result = const_to_valtree_inner(&ecx, &place, &mut num_nodes);
+
+    match valtree_result {
+        Ok(valtree) => Ok(Some(valtree)),
+        Err(err) => {
+            let did = cid.instance.def_id();
+            let s = cid.display(tcx);
+            match err {
+                ValTreeCreationError::NodesOverflow => {
+                    let msg = format!("maximum number of nodes exceeded in constant {}", &s);
+                    let mut diag = match tcx.hir().span_if_local(did) {
+                        Some(span) => tcx.sess.struct_span_err(span, &msg),
+                        None => tcx.sess.struct_err(&msg),
+                    };
+                    diag.emit();
+
+                    Ok(None)
+                }
+                ValTreeCreationError::NonSupportedType | ValTreeCreationError::Other => Ok(None),
+            }
         }
-        ty::Tuple(substs) => (substs.len(), None, op),
-        _ => bug!("cannot destructure constant {:?}", val),
-    };
+    }
+}
 
-    let fields = (0..field_count)
-        .map(|i| {
-            let field_op = ecx.operand_field(&down, i)?;
-            let val = op_to_const(&ecx, &field_op);
-            Ok(ty::Const::from_value(tcx, val, field_op.layout.ty))
-        })
-        .collect::<InterpResult<'tcx, Vec<_>>>()?;
-    let fields = tcx.arena.alloc_from_iter(fields);
+/// Tries to destructure constants of type Array or Adt into the constants
+/// of its fields.
+pub(crate) fn try_destructure_const<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    const_: ty::Const<'tcx>,
+) -> Option<ty::DestructuredConst<'tcx>> {
+    if let ty::ConstKind::Value(valtree) = const_.kind() {
+        let branches = match valtree {
+            ty::ValTree::Branch(b) => b,
+            _ => return None,
+        };
 
-    Ok(mir::DestructuredConst { variant, fields })
+        let (fields, variant) = match const_.ty().kind() {
+            ty::Array(inner_ty, _) | ty::Slice(inner_ty) => {
+                // construct the consts for the elements of the array/slice
+                let field_consts = branches
+                    .iter()
+                    .map(|b| {
+                        tcx.mk_const(ty::ConstS { kind: ty::ConstKind::Value(*b), ty: *inner_ty })
+                    })
+                    .collect::<Vec<_>>();
+                debug!(?field_consts);
+
+                (field_consts, None)
+            }
+            ty::Adt(def, _) if def.variants().is_empty() => bug!("unreachable"),
+            ty::Adt(def, substs) => {
+                let variant_idx = if def.is_enum() {
+                    VariantIdx::from_u32(branches[0].unwrap_leaf().try_to_u32().ok()?)
+                } else {
+                    VariantIdx::from_u32(0)
+                };
+                let fields = &def.variant(variant_idx).fields;
+                let mut field_consts = Vec::with_capacity(fields.len());
+
+                // Note: First element inValTree corresponds to variant of enum
+                let mut valtree_idx = if def.is_enum() { 1 } else { 0 };
+                for field in fields {
+                    let field_ty = field.ty(tcx, substs);
+                    let field_valtree = branches[valtree_idx]; // first element of branches is variant
+                    let field_const = tcx.mk_const(ty::ConstS {
+                        kind: ty::ConstKind::Value(field_valtree),
+                        ty: field_ty,
+                    });
+                    field_consts.push(field_const);
+                    valtree_idx += 1;
+                }
+                debug!(?field_consts);
+
+                (field_consts, Some(variant_idx))
+            }
+            ty::Tuple(elem_tys) => {
+                let fields = elem_tys
+                    .iter()
+                    .enumerate()
+                    .map(|(i, elem_ty)| {
+                        let elem_valtree = branches[i];
+                        tcx.mk_const(ty::ConstS {
+                            kind: ty::ConstKind::Value(elem_valtree),
+                            ty: elem_ty,
+                        })
+                    })
+                    .collect::<Vec<_>>();
+
+                (fields, None)
+            }
+            _ => bug!("cannot destructure constant {:?}", const_),
+        };
+
+        let fields = tcx.arena.alloc_from_iter(fields.into_iter());
+
+        Some(ty::DestructuredConst { variant, fields })
+    } else {
+        None
+    }
 }
 
 #[instrument(skip(tcx), level = "debug")]
-pub(crate) fn deref_const<'tcx>(
+pub(crate) fn try_destructure_mir_constant<'tcx>(
     tcx: TyCtxt<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
-    val: ty::Const<'tcx>,
-) -> ty::Const<'tcx> {
-    trace!("deref_const: {:?}", val);
+    val: mir::ConstantKind<'tcx>,
+) -> InterpResult<'tcx, mir::DestructuredMirConstant<'tcx>> {
+    trace!("destructure_mir_constant: {:?}", val);
     let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, false);
-    let op = ecx.const_to_op(val, None).unwrap();
+    let op = ecx.mir_const_to_op(&val, None)?;
+
+    // We go to `usize` as we cannot allocate anything bigger anyway.
+    let (field_count, variant, down) = match val.ty().kind() {
+        ty::Array(_, len) => (len.eval_usize(tcx, param_env) as usize, None, op),
+        ty::Adt(def, _) if def.variants().is_empty() => {
+            throw_ub!(Unreachable)
+        }
+        ty::Adt(def, _) => {
+            let variant = ecx.read_discriminant(&op)?.1;
+            let down = ecx.operand_downcast(&op, variant)?;
+            (def.variants()[variant].fields.len(), Some(variant), down)
+        }
+        ty::Tuple(substs) => (substs.len(), None, op),
+        _ => bug!("cannot destructure mir constant {:?}", val),
+    };
+
+    let fields_iter = (0..field_count)
+        .map(|i| {
+            let field_op = ecx.operand_field(&down, i)?;
+            let val = op_to_const(&ecx, &field_op);
+            Ok(mir::ConstantKind::Val(val, field_op.layout.ty))
+        })
+        .collect::<InterpResult<'tcx, Vec<_>>>()?;
+    let fields = tcx.arena.alloc_from_iter(fields_iter);
+
+    Ok(mir::DestructuredMirConstant { variant, fields })
+}
+
+#[instrument(skip(tcx), level = "debug")]
+pub(crate) fn deref_mir_constant<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+    val: mir::ConstantKind<'tcx>,
+) -> mir::ConstantKind<'tcx> {
+    let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, false);
+    let op = ecx.mir_const_to_op(&val, None).unwrap();
     let mplace = ecx.deref_operand(&op).unwrap();
     if let Some(alloc_id) = mplace.ptr.provenance {
         assert_eq!(
-            tcx.get_global_alloc(alloc_id).unwrap().unwrap_memory().inner().mutability,
+            tcx.get_global_alloc(alloc_id).unwrap().unwrap_memory().0.0.mutability,
             Mutability::Not,
-            "deref_const cannot be used with mutable allocations as \
+            "deref_mir_constant cannot be used with mutable allocations as \
             that could allow pattern matching to observe mutable statics",
         );
     }
 
     let ty = match mplace.meta {
         MemPlaceMeta::None => mplace.layout.ty,
-        MemPlaceMeta::Poison => bug!("poison metadata in `deref_const`: {:#?}", mplace),
+        MemPlaceMeta::Poison => bug!("poison metadata in `deref_mir_constant`: {:#?}", mplace),
         // In case of unsized types, figure out the real type behind.
         MemPlaceMeta::Meta(scalar) => match mplace.layout.ty.kind() {
             ty::Str => bug!("there's no sized equivalent of a `str`"),
@@ -111,5 +238,5 @@
         },
     };
 
-    tcx.mk_const(ty::ConstS { val: ty::ConstKind::Value(op_to_const(&ecx, &mplace.into())), ty })
+    mir::ConstantKind::Val(op_to_const(&ecx, &mplace.into()), ty)
 }
diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs
index f57f25c..4849a07 100644
--- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs
+++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs
@@ -1,41 +1,23 @@
 use super::eval_queries::{mk_eval_cx, op_to_const};
 use super::machine::CompileTimeEvalContext;
+use super::{ValTreeCreationError, ValTreeCreationResult, VALTREE_MAX_NODES};
 use crate::interpret::{
     intern_const_alloc_recursive, ConstValue, ImmTy, Immediate, InternKind, MemPlaceMeta,
     MemoryKind, PlaceTy, Scalar, ScalarMaybeUninit,
 };
-use rustc_middle::mir::interpret::ConstAlloc;
+use crate::interpret::{MPlaceTy, Value};
 use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt};
 use rustc_span::source_map::DUMMY_SP;
 use rustc_target::abi::{Align, VariantIdx};
 
-use crate::interpret::MPlaceTy;
-use crate::interpret::Value;
-
-/// Convert an evaluated constant to a type level constant
-#[instrument(skip(tcx), level = "debug")]
-pub(crate) fn const_to_valtree<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
-    raw: ConstAlloc<'tcx>,
-) -> Option<ty::ValTree<'tcx>> {
-    let ecx = mk_eval_cx(
-        tcx, DUMMY_SP, param_env,
-        // It is absolutely crucial for soundness that
-        // we do not read from static items or other mutable memory.
-        false,
-    );
-    let place = ecx.raw_const_to_mplace(raw).unwrap();
-    const_to_valtree_inner(&ecx, &place)
-}
-
 #[instrument(skip(ecx), level = "debug")]
 fn branches<'tcx>(
     ecx: &CompileTimeEvalContext<'tcx, 'tcx>,
     place: &MPlaceTy<'tcx>,
     n: usize,
     variant: Option<VariantIdx>,
-) -> Option<ty::ValTree<'tcx>> {
+    num_nodes: &mut usize,
+) -> ValTreeCreationResult<'tcx> {
     let place = match variant {
         Some(variant) => ecx.mplace_downcast(&place, variant).unwrap(),
         None => *place,
@@ -43,82 +25,116 @@
     let variant = variant.map(|variant| Some(ty::ValTree::Leaf(ScalarInt::from(variant.as_u32()))));
     debug!(?place, ?variant);
 
-    let fields = (0..n).map(|i| {
+    let mut fields = Vec::with_capacity(n);
+    for i in 0..n {
         let field = ecx.mplace_field(&place, i).unwrap();
-        const_to_valtree_inner(ecx, &field)
-    });
-    // For enums, we preped their variant index before the variant's fields so we can figure out
+        let valtree = const_to_valtree_inner(ecx, &field, num_nodes)?;
+        fields.push(Some(valtree));
+    }
+
+    // For enums, we prepend their variant index before the variant's fields so we can figure out
     // the variant again when just seeing a valtree.
-    let branches = variant.into_iter().chain(fields);
-    Some(ty::ValTree::Branch(ecx.tcx.arena.alloc_from_iter(branches.collect::<Option<Vec<_>>>()?)))
+    let branches = variant
+        .into_iter()
+        .chain(fields.into_iter())
+        .collect::<Option<Vec<_>>>()
+        .expect("should have already checked for errors in ValTree creation");
+
+    // Have to account for ZSTs here
+    if branches.len() == 0 {
+        *num_nodes += 1;
+    }
+
+    Ok(ty::ValTree::Branch(ecx.tcx.arena.alloc_from_iter(branches)))
 }
 
 #[instrument(skip(ecx), level = "debug")]
 fn slice_branches<'tcx>(
     ecx: &CompileTimeEvalContext<'tcx, 'tcx>,
     place: &MPlaceTy<'tcx>,
-) -> Option<ty::ValTree<'tcx>> {
+    num_nodes: &mut usize,
+) -> ValTreeCreationResult<'tcx> {
     let n = place
         .len(&ecx.tcx.tcx)
         .unwrap_or_else(|_| panic!("expected to use len of place {:?}", place));
-    let branches = (0..n).map(|i| {
-        let place_elem = ecx.mplace_index(place, i).unwrap();
-        const_to_valtree_inner(ecx, &place_elem)
-    });
 
-    Some(ty::ValTree::Branch(ecx.tcx.arena.alloc_from_iter(branches.collect::<Option<Vec<_>>>()?)))
+    let mut elems = Vec::with_capacity(n as usize);
+    for i in 0..n {
+        let place_elem = ecx.mplace_index(place, i).unwrap();
+        let valtree = const_to_valtree_inner(ecx, &place_elem, num_nodes)?;
+        elems.push(valtree);
+    }
+
+    Ok(ty::ValTree::Branch(ecx.tcx.arena.alloc_from_iter(elems)))
 }
 
 #[instrument(skip(ecx), level = "debug")]
-fn const_to_valtree_inner<'tcx>(
+pub(crate) fn const_to_valtree_inner<'tcx>(
     ecx: &CompileTimeEvalContext<'tcx, 'tcx>,
     place: &MPlaceTy<'tcx>,
-) -> Option<ty::ValTree<'tcx>> {
-    match place.layout.ty.kind() {
-        ty::FnDef(..) => Some(ty::ValTree::zst()),
+    num_nodes: &mut usize,
+) -> ValTreeCreationResult<'tcx> {
+    let ty = place.layout.ty;
+    debug!("ty kind: {:?}", ty.kind());
+
+    if *num_nodes >= VALTREE_MAX_NODES {
+        return Err(ValTreeCreationError::NodesOverflow);
+    }
+
+    match ty.kind() {
+        ty::FnDef(..) => {
+            *num_nodes += 1;
+            Ok(ty::ValTree::zst())
+        }
         ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Char => {
-            let val = ecx.read_immediate(&place.into()).unwrap();
+            let Ok(val) = ecx.read_immediate(&place.into()) else {
+                return Err(ValTreeCreationError::Other);
+            };
             let val = val.to_scalar().unwrap();
-            Some(ty::ValTree::Leaf(val.assert_int()))
+            *num_nodes += 1;
+
+            Ok(ty::ValTree::Leaf(val.assert_int()))
         }
 
         // Raw pointers are not allowed in type level constants, as we cannot properly test them for
         // equality at compile-time (see `ptr_guaranteed_eq`/`_ne`).
         // Technically we could allow function pointers (represented as `ty::Instance`), but this is not guaranteed to
         // agree with runtime equality tests.
-        ty::FnPtr(_) | ty::RawPtr(_) => None,
+        ty::FnPtr(_) | ty::RawPtr(_) => Err(ValTreeCreationError::NonSupportedType),
 
         ty::Ref(_, _, _)  => {
-            let derefd_place = ecx.deref_operand(&place.into()).unwrap_or_else(|e| bug!("couldn't deref {:?}, error: {:?}", place, e));
+            let Ok(derefd_place)= ecx.deref_operand(&place.into()) else {
+                return Err(ValTreeCreationError::Other);
+            };
             debug!(?derefd_place);
 
-            const_to_valtree_inner(ecx, &derefd_place)
+            const_to_valtree_inner(ecx, &derefd_place, num_nodes)
         }
 
         ty::Str | ty::Slice(_) | ty::Array(_, _) => {
-            let valtree = slice_branches(ecx, place);
-            debug!(?valtree);
-
-            valtree
+            slice_branches(ecx, place, num_nodes)
         }
         // Trait objects are not allowed in type level constants, as we have no concept for
         // resolving their backing type, even if we can do that at const eval time. We may
         // hypothetically be able to allow `dyn StructuralEq` trait objects in the future,
         // but it is unclear if this is useful.
-        ty::Dynamic(..) => None,
+        ty::Dynamic(..) => Err(ValTreeCreationError::NonSupportedType),
 
-        ty::Tuple(substs) => branches(ecx, place, substs.len(), None),
+        ty::Tuple(elem_tys) => {
+            branches(ecx, place, elem_tys.len(), None, num_nodes)
+        }
 
         ty::Adt(def, _) => {
             if def.is_union() {
-                return None
+                return Err(ValTreeCreationError::NonSupportedType);
             } else if def.variants().is_empty() {
                 bug!("uninhabited types should have errored and never gotten converted to valtree")
             }
 
-            let variant = ecx.read_discriminant(&place.into()).unwrap().1;
-
-            branches(ecx, place, def.variant(variant).fields.len(), def.is_enum().then_some(variant))
+            let Ok((_, variant)) = ecx.read_discriminant(&place.into()) else {
+                return Err(ValTreeCreationError::Other);
+            };
+            branches(ecx, place, def.variant(variant).fields.len(), def.is_enum().then_some(variant), num_nodes)
         }
 
         ty::Never
@@ -136,7 +152,7 @@
         // FIXME(oli-obk): we can probably encode closures just like structs
         | ty::Closure(..)
         | ty::Generator(..)
-        | ty::GeneratorWitness(..) => None,
+        | ty::GeneratorWitness(..) => Err(ValTreeCreationError::NonSupportedType),
     }
 }
 
@@ -216,17 +232,16 @@
         // Get the size of the memory behind the DST
         let dst_size = unsized_inner_ty_size.checked_mul(num_elems as u64, &tcx).unwrap();
 
-        let ptr = ecx
-            .allocate_ptr(
-                size_of_sized_part.checked_add(dst_size, &tcx).unwrap(),
-                Align::from_bytes(1).unwrap(),
-                MemoryKind::Stack,
-            )
-            .unwrap();
+        let size = size_of_sized_part.checked_add(dst_size, &tcx).unwrap();
+        let align = Align::from_bytes(size.bytes().next_power_of_two()).unwrap();
+        let ptr = ecx.allocate_ptr(size, align, MemoryKind::Stack).unwrap();
         debug!(?ptr);
 
-        let mut place = MPlaceTy::from_aligned_ptr(ptr.into(), layout);
-        place.meta = MemPlaceMeta::Meta(Scalar::from_u64(num_elems as u64));
+        let place = MPlaceTy::from_aligned_ptr_with_meta(
+            ptr.into(),
+            layout,
+            MemPlaceMeta::Meta(Scalar::from_machine_usize(num_elems as u64, &tcx)),
+        );
         debug!(?place);
 
         place
@@ -237,7 +252,7 @@
 
 /// Converts a `ValTree` to a `ConstValue`, which is needed after mir
 /// construction has finished.
-// FIXME Merge `valtree_to_const_value` and `fill_place_recursively` into one function
+// FIXME Merge `valtree_to_const_value` and `valtree_into_mplace` into one function
 #[instrument(skip(tcx), level = "debug")]
 pub fn valtree_to_const_value<'tcx>(
     tcx: TyCtxt<'tcx>,
@@ -275,7 +290,7 @@
             };
             debug!(?place);
 
-            fill_place_recursively(&mut ecx, &mut place, valtree);
+            valtree_into_mplace(&mut ecx, &mut place, valtree);
             dump_place(&ecx, place.into());
             intern_const_alloc_recursive(&mut ecx, InternKind::Constant, &place).unwrap();
 
@@ -315,9 +330,8 @@
     }
 }
 
-// FIXME Needs a better/correct name
 #[instrument(skip(ecx), level = "debug")]
-fn fill_place_recursively<'tcx>(
+fn valtree_into_mplace<'tcx>(
     ecx: &mut CompileTimeEvalContext<'tcx, 'tcx>,
     place: &mut MPlaceTy<'tcx>,
     valtree: ty::ValTree<'tcx>,
@@ -349,14 +363,15 @@
             let mut pointee_place = create_pointee_place(ecx, *inner_ty, valtree);
             debug!(?pointee_place);
 
-            fill_place_recursively(ecx, &mut pointee_place, valtree);
+            valtree_into_mplace(ecx, &mut pointee_place, valtree);
             dump_place(ecx, pointee_place.into());
             intern_const_alloc_recursive(ecx, InternKind::Constant, &pointee_place).unwrap();
 
             let imm = match inner_ty.kind() {
                 ty::Slice(_) | ty::Str => {
                     let len = valtree.unwrap_branch().len();
-                    let len_scalar = ScalarMaybeUninit::Scalar(Scalar::from_u64(len as u64));
+                    let len_scalar =
+                        ScalarMaybeUninit::Scalar(Scalar::from_machine_usize(len as u64, &tcx));
 
                     Immediate::ScalarPair(
                         ScalarMaybeUninit::from_maybe_pointer((*pointee_place).ptr, &tcx),
@@ -427,7 +442,10 @@
                         place
                             .offset(
                                 offset,
-                                MemPlaceMeta::Meta(Scalar::from_u64(num_elems as u64)),
+                                MemPlaceMeta::Meta(Scalar::from_machine_usize(
+                                    num_elems as u64,
+                                    &tcx,
+                                )),
                                 inner_layout,
                                 &tcx,
                             )
@@ -437,7 +455,7 @@
                 };
 
                 debug!(?place_inner);
-                fill_place_recursively(ecx, &mut place_inner, *inner_valtree);
+                valtree_into_mplace(ecx, &mut place_inner, *inner_valtree);
                 dump_place(&ecx, place_inner.into());
             }
 
diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs
index 92eeafc..fb484fb 100644
--- a/compiler/rustc_const_eval/src/interpret/cast.rs
+++ b/compiler/rustc_const_eval/src/interpret/cast.rs
@@ -1,3 +1,4 @@
+use std::assert_matches::assert_matches;
 use std::convert::TryFrom;
 
 use rustc_apfloat::ieee::{Double, Single};
@@ -8,6 +9,7 @@
 use rustc_middle::ty::layout::{IntegerExt, LayoutOf, TyAndLayout};
 use rustc_middle::ty::{self, FloatTy, Ty, TypeAndMut};
 use rustc_target::abi::{Integer, Variants};
+use rustc_type_ir::sty::TyKind::*;
 
 use super::{
     util::ensure_monomorphic_enough, FnVal, ImmTy, Immediate, InterpCx, Machine, OpTy, PlaceTy,
@@ -29,6 +31,18 @@
                 self.unsize_into(src, cast_ty, dest)?;
             }
 
+            PointerExposeAddress => {
+                let src = self.read_immediate(src)?;
+                let res = self.pointer_expose_address_cast(&src, cast_ty)?;
+                self.write_immediate(res, dest)?;
+            }
+
+            PointerFromExposedAddress => {
+                let src = self.read_immediate(src)?;
+                let res = self.pointer_from_exposed_address_cast(&src, cast_ty)?;
+                self.write_immediate(res, dest)?;
+            }
+
             Misc => {
                 let src = self.read_immediate(src)?;
                 let res = self.misc_cast(&src, cast_ty)?;
@@ -102,7 +116,7 @@
         src: &ImmTy<'tcx, M::PointerTag>,
         cast_ty: Ty<'tcx>,
     ) -> InterpResult<'tcx, Immediate<M::PointerTag>> {
-        use rustc_middle::ty::TyKind::*;
+        use rustc_type_ir::sty::TyKind::*;
         trace!("Casting {:?}: {:?} to {:?}", *src, src.layout.ty, cast_ty);
 
         match src.layout.ty.kind() {
@@ -173,26 +187,44 @@
 
         // # The remaining source values are scalar and "int-like".
         let scalar = src.to_scalar()?;
-
-        // If we are casting from a pointer to something
-        // that is not a pointer, mark the pointer as exposed
-        if src.layout.ty.is_any_ptr() && !cast_ty.is_any_ptr() {
-            let ptr = self.scalar_to_ptr(scalar)?;
-
-            match ptr.into_pointer_or_addr() {
-                Ok(ptr) => {
-                    M::expose_ptr(self, ptr)?;
-                }
-                Err(_) => {
-                    // do nothing, exposing an invalid pointer
-                    // has no meaning
-                }
-            };
-        }
-
         Ok(self.cast_from_int_like(scalar, src.layout, cast_ty)?.into())
     }
 
+    pub fn pointer_expose_address_cast(
+        &mut self,
+        src: &ImmTy<'tcx, M::PointerTag>,
+        cast_ty: Ty<'tcx>,
+    ) -> InterpResult<'tcx, Immediate<M::PointerTag>> {
+        assert_matches!(src.layout.ty.kind(), ty::RawPtr(_) | ty::FnPtr(_));
+        assert!(cast_ty.is_integral());
+
+        let scalar = src.to_scalar()?;
+        let ptr = self.scalar_to_ptr(scalar)?;
+        match ptr.into_pointer_or_addr() {
+            Ok(ptr) => M::expose_ptr(self, ptr)?,
+            Err(_) => {} // do nothing, exposing an invalid pointer has no meaning
+        };
+        Ok(self.cast_from_int_like(scalar, src.layout, cast_ty)?.into())
+    }
+
+    pub fn pointer_from_exposed_address_cast(
+        &mut self,
+        src: &ImmTy<'tcx, M::PointerTag>,
+        cast_ty: Ty<'tcx>,
+    ) -> InterpResult<'tcx, Immediate<M::PointerTag>> {
+        assert!(src.layout.ty.is_integral());
+        assert_matches!(cast_ty.kind(), ty::RawPtr(_));
+
+        // First cast to usize.
+        let scalar = src.to_scalar()?;
+        let addr = self.cast_from_int_like(scalar, src.layout, self.tcx.types.usize)?;
+        let addr = addr.to_machine_usize(self)?;
+
+        // Then turn address into pointer.
+        let ptr = M::ptr_from_addr_cast(&self, addr)?;
+        Ok(Scalar::from_maybe_pointer(ptr, self).into())
+    }
+
     pub fn cast_from_int_like(
         &self,
         scalar: Scalar<M::PointerTag>, // input value (there is no ScalarTy so we separate data+layout)
@@ -205,7 +237,6 @@
         let v = scalar.to_bits(src_layout.size)?;
         let v = if signed { self.sign_extend(v, src_layout) } else { v };
         trace!("cast_from_scalar: {}, {} -> {}", v, src_layout.ty, cast_ty);
-        use rustc_middle::ty::TyKind::*;
 
         Ok(match *cast_ty.kind() {
             Int(_) | Uint(_) => {
@@ -218,19 +249,6 @@
                 Scalar::from_uint(v, size)
             }
 
-            RawPtr(_) => {
-                assert!(src_layout.ty.is_integral());
-
-                let size = self.pointer_size();
-                let addr = u64::try_from(size.truncate(v)).unwrap();
-
-                let ptr = M::ptr_from_addr_cast(&self, addr);
-                if addr == 0 {
-                    assert!(ptr.provenance.is_none(), "null pointer can never have an AllocId");
-                }
-                Scalar::from_maybe_pointer(ptr, self)
-            }
-
             Float(FloatTy::F32) if signed => Scalar::from_f32(Single::from_i128(v as i128).value),
             Float(FloatTy::F64) if signed => Scalar::from_f64(Double::from_i128(v as i128).value),
             Float(FloatTy::F32) => Scalar::from_f32(Single::from_u128(v).value),
@@ -250,7 +268,7 @@
     where
         F: Float + Into<Scalar<M::PointerTag>> + FloatConvert<Single> + FloatConvert<Double>,
     {
-        use rustc_middle::ty::TyKind::*;
+        use rustc_type_ir::sty::TyKind::*;
         match *dest_ty.kind() {
             // float -> uint
             Uint(t) => {
diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs
index dfb81a2..1c1bbd3 100644
--- a/compiler/rustc_const_eval/src/interpret/eval_context.rs
+++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs
@@ -15,7 +15,7 @@
 use rustc_middle::ty::{
     self, query::TyCtxtAt, subst::SubstsRef, ParamEnv, Ty, TyCtxt, TypeFoldable,
 };
-use rustc_mir_dataflow::storage::AlwaysLiveLocals;
+use rustc_mir_dataflow::storage::always_live_locals;
 use rustc_query_system::ich::StableHashingContext;
 use rustc_session::Limit;
 use rustc_span::{Pos, Span};
@@ -105,7 +105,7 @@
 
     /// The location where the result of the current stack frame should be written to,
     /// and its layout in the caller.
-    pub return_place: Option<PlaceTy<'tcx, Tag>>,
+    pub return_place: PlaceTy<'tcx, Tag>,
 
     /// The list of locals for this stack frame, stored in order as
     /// `[return_ptr, arguments..., variables..., temporaries...]`.
@@ -126,7 +126,9 @@
     /// this frame (can happen e.g. during frame initialization, and during unwinding on
     /// frames without cleanup code).
     /// We basically abuse `Result` as `Either`.
-    pub(super) loc: Result<mir::Location, Span>,
+    ///
+    /// Needs to be public because ConstProp does unspeakable things to it.
+    pub loc: Result<mir::Location, Span>,
 }
 
 /// What we store about a frame in an interpreter backtrace.
@@ -320,6 +322,7 @@
 
     #[inline]
     fn layout_tcx_at_span(&self) -> Span {
+        // Using the cheap root span for performance.
         self.tcx.span
     }
 
@@ -520,13 +523,13 @@
         frame
             .instance
             .try_subst_mir_and_normalize_erasing_regions(*self.tcx, self.param_env, value)
-            .or_else(|e| {
+            .map_err(|e| {
                 self.tcx.sess.delay_span_bug(
                     self.cur_span(),
                     format!("failed to normalize {}", e.get_type_for_failure()).as_str(),
                 );
 
-                Err(InterpError::InvalidProgram(InvalidProgramInfo::TooGeneric))
+                InterpError::InvalidProgram(InvalidProgramInfo::TooGeneric)
             })
     }
 
@@ -676,7 +679,7 @@
         &mut self,
         instance: ty::Instance<'tcx>,
         body: &'mir mir::Body<'tcx>,
-        return_place: Option<&PlaceTy<'tcx, M::PointerTag>>,
+        return_place: &PlaceTy<'tcx, M::PointerTag>,
         return_to_block: StackPopCleanup,
     ) -> InterpResult<'tcx> {
         trace!("body: {:#?}", body);
@@ -685,7 +688,7 @@
             body,
             loc: Err(body.span), // Span used for errors caused during preamble.
             return_to_block,
-            return_place: return_place.copied(),
+            return_place: *return_place,
             // empty local array, we fill it in below, after we are inside the stack frame and
             // all methods actually know about the frame
             locals: IndexVec::new(),
@@ -715,7 +718,7 @@
 
         // Now mark those locals as dead that we do not want to initialize
         // Mark locals that use `Storage*` annotations as dead on function entry.
-        let always_live = AlwaysLiveLocals::new(self.body());
+        let always_live = always_live_locals(self.body());
         for local in locals.indices() {
             if !always_live.contains(local) {
                 locals[local].value = LocalValue::Dead;
@@ -807,14 +810,9 @@
             self.stack_mut().pop().expect("tried to pop a stack frame, but there were none");
 
         if !unwinding {
-            // Copy the return value to the caller's stack frame.
-            if let Some(ref return_place) = frame.return_place {
-                let op = self.access_local(&frame, mir::RETURN_PLACE, None)?;
-                self.copy_op_transmute(&op, return_place)?;
-                trace!("{:?}", self.dump_place(**return_place));
-            } else {
-                throw_ub!(Unreachable);
-            }
+            let op = self.access_local(&frame, mir::RETURN_PLACE, None)?;
+            self.copy_op_transmute(&op, &frame.return_place)?;
+            trace!("{:?}", self.dump_place(*frame.return_place));
         }
 
         let return_to_block = frame.return_to_block;
@@ -928,7 +926,8 @@
             self.param_env
         };
         let param_env = param_env.with_const();
-        let val = self.tcx.eval_to_allocation_raw(param_env.and(gid))?;
+        // Use a precise span for better cycle errors.
+        let val = self.tcx.at(self.cur_span()).eval_to_allocation_raw(param_env.and(gid))?;
         self.raw_const_to_mplace(val)
     }
 
@@ -1014,11 +1013,7 @@
                     }
                 }
 
-                write!(
-                    fmt,
-                    ": {:?}",
-                    self.ecx.dump_allocs(allocs.into_iter().filter_map(|x| x).collect())
-                )
+                write!(fmt, ": {:?}", self.ecx.dump_allocs(allocs.into_iter().flatten().collect()))
             }
             Place::Ptr(mplace) => match mplace.ptr.provenance.and_then(Provenance::get_alloc_id) {
                 Some(alloc_id) => write!(
@@ -1055,7 +1050,7 @@
         body.hash_stable(hcx, hasher);
         instance.hash_stable(hcx, hasher);
         return_to_block.hash_stable(hcx, hasher);
-        return_place.as_ref().map(|r| &**r).hash_stable(hcx, hasher);
+        return_place.hash_stable(hcx, hasher);
         locals.hash_stable(hcx, hasher);
         loc.hash_stable(hcx, hasher);
         extra.hash_stable(hcx, hasher);
diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
index 59ea40d..e51c51c 100644
--- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs
+++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
@@ -15,7 +15,7 @@
 use rustc_middle::ty::subst::SubstsRef;
 use rustc_middle::ty::{Ty, TyCtxt};
 use rustc_span::symbol::{sym, Symbol};
-use rustc_target::abi::{Abi, Align, Primitive, Size};
+use rustc_target::abi::{Abi, Align, InitKind, Primitive, Size};
 
 use super::{
     util::ensure_monomorphic_enough, CheckInAllocMsg, ImmTy, InterpCx, Machine, OpTy, PlaceTy,
@@ -44,7 +44,7 @@
 
 /// The logic for all nullary intrinsics is implemented here. These intrinsics don't get evaluated
 /// inside an `InterpCx` and instead have their value computed directly from rustc internal info.
-crate fn eval_nullary_intrinsic<'tcx>(
+pub(crate) fn eval_nullary_intrinsic<'tcx>(
     tcx: TyCtxt<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
     def_id: DefId,
@@ -115,13 +115,14 @@
         &mut self,
         instance: ty::Instance<'tcx>,
         args: &[OpTy<'tcx, M::PointerTag>],
-        ret: Option<(&PlaceTy<'tcx, M::PointerTag>, mir::BasicBlock)>,
+        dest: &PlaceTy<'tcx, M::PointerTag>,
+        ret: Option<mir::BasicBlock>,
     ) -> InterpResult<'tcx, bool> {
         let substs = instance.substs;
         let intrinsic_name = self.tcx.item_name(instance.def_id());
 
         // First handle intrinsics without return place.
-        let (dest, ret) = match ret {
+        let ret = match ret {
             None => match intrinsic_name {
                 sym::transmute => throw_ub_format!("transmuting to uninhabited type"),
                 sym::abort => M::abort(self, "the program aborted execution".to_owned())?,
@@ -168,7 +169,7 @@
                     sym::needs_drop => self.tcx.types.bool,
                     sym::type_id => self.tcx.types.u64,
                     sym::type_name => self.tcx.mk_static_str(),
-                    _ => bug!("already checked for nullary intrinsics"),
+                    _ => bug!(),
                 };
                 let val =
                     self.tcx.const_eval_global_id(self.param_env, gid, Some(self.tcx.span))?;
@@ -214,7 +215,7 @@
                     sym::add_with_overflow => BinOp::Add,
                     sym::sub_with_overflow => BinOp::Sub,
                     sym::mul_with_overflow => BinOp::Mul,
-                    _ => bug!("Already checked for int ops"),
+                    _ => bug!(),
                 };
                 self.binop_with_overflow(bin_op, &lhs, &rhs, dest)?;
             }
@@ -250,7 +251,7 @@
                     sym::unchecked_mul => BinOp::Mul,
                     sym::unchecked_div => BinOp::Div,
                     sym::unchecked_rem => BinOp::Rem,
-                    _ => bug!("Already checked for int ops"),
+                    _ => bug!(),
                 };
                 let (val, overflowed, _ty) = self.overflowing_binary_op(bin_op, &l, &r)?;
                 if overflowed {
@@ -312,78 +313,82 @@
                 let a = self.read_pointer(&args[0])?;
                 let b = self.read_pointer(&args[1])?;
 
-                // Special case: if both scalars are *equal integers*
-                // and not null, we pretend there is an allocation of size 0 right there,
-                // and their offset is 0. (There's never a valid object at null, making it an
-                // exception from the exception.)
-                // This is the dual to the special exception for offset-by-0
-                // in the inbounds pointer offset operation (see `ptr_offset_inbounds` below).
-                match (self.ptr_try_get_alloc_id(a), self.ptr_try_get_alloc_id(b)) {
-                    (Err(a), Err(b)) if a == b && a != 0 => {
-                        // Both are the same non-null integer.
-                        self.write_scalar(Scalar::from_machine_isize(0, self), dest)?;
-                    }
-                    (Err(offset), _) | (_, Err(offset)) => {
-                        throw_ub!(DanglingIntPointer(offset, CheckInAllocMsg::OffsetFromTest));
-                    }
-                    (Ok((a_alloc_id, a_offset, _)), Ok((b_alloc_id, b_offset, _))) => {
-                        // Both are pointers. They must be into the same allocation.
-                        if a_alloc_id != b_alloc_id {
+                let usize_layout = self.layout_of(self.tcx.types.usize)?;
+                let isize_layout = self.layout_of(self.tcx.types.isize)?;
+
+                // Get offsets for both that are at least relative to the same base.
+                let (a_offset, b_offset) =
+                    match (self.ptr_try_get_alloc_id(a), self.ptr_try_get_alloc_id(b)) {
+                        (Err(a), Err(b)) => {
+                            // Neither poiner points to an allocation.
+                            // If these are inequal or null, this *will* fail the deref check below.
+                            (a, b)
+                        }
+                        (Err(_), _) | (_, Err(_)) => {
+                            // We managed to find a valid allocation for one pointer, but not the other.
+                            // That means they are definitely not pointing to the same allocation.
                             throw_ub_format!(
-                                "{} cannot compute offset of pointers into different allocations.",
-                                intrinsic_name,
+                                "{} called on pointers into different allocations",
+                                intrinsic_name
                             );
                         }
-                        // And they must both be valid for zero-sized accesses ("in-bounds or one past the end").
-                        self.check_ptr_access_align(
-                            a,
-                            Size::ZERO,
-                            Align::ONE,
-                            CheckInAllocMsg::OffsetFromTest,
-                        )?;
-                        self.check_ptr_access_align(
-                            b,
-                            Size::ZERO,
-                            Align::ONE,
-                            CheckInAllocMsg::OffsetFromTest,
-                        )?;
-
-                        if intrinsic_name == sym::ptr_offset_from_unsigned && a_offset < b_offset {
-                            throw_ub_format!(
-                                "{} cannot compute a negative offset, but {} < {}",
-                                intrinsic_name,
-                                a_offset.bytes(),
-                                b_offset.bytes(),
-                            );
+                        (Ok((a_alloc_id, a_offset, _)), Ok((b_alloc_id, b_offset, _))) => {
+                            // Found allocation for both. They must be into the same allocation.
+                            if a_alloc_id != b_alloc_id {
+                                throw_ub_format!(
+                                    "{} called on pointers into different allocations",
+                                    intrinsic_name
+                                );
+                            }
+                            // Use these offsets for distance calculation.
+                            (a_offset.bytes(), b_offset.bytes())
                         }
+                    };
 
-                        // Compute offset.
-                        let usize_layout = self.layout_of(self.tcx.types.usize)?;
-                        let isize_layout = self.layout_of(self.tcx.types.isize)?;
-                        let ret_layout = if intrinsic_name == sym::ptr_offset_from {
-                            isize_layout
-                        } else {
-                            usize_layout
-                        };
-
-                        // The subtraction is always done in `isize` to enforce
-                        // the "no more than `isize::MAX` apart" requirement.
-                        let a_offset = ImmTy::from_uint(a_offset.bytes(), isize_layout);
-                        let b_offset = ImmTy::from_uint(b_offset.bytes(), isize_layout);
-                        let (val, overflowed, _ty) =
-                            self.overflowing_binary_op(BinOp::Sub, &a_offset, &b_offset)?;
-                        if overflowed {
-                            throw_ub_format!("Pointers were too far apart for {}", intrinsic_name);
-                        }
-
-                        let pointee_layout = self.layout_of(substs.type_at(0))?;
-                        // This re-interprets an isize at ret_layout, but we already checked
-                        // that if ret_layout is usize, then the result must be non-negative.
-                        let val = ImmTy::from_scalar(val, ret_layout);
-                        let size = ImmTy::from_int(pointee_layout.size.bytes(), ret_layout);
-                        self.exact_div(&val, &size, dest)?;
+                // Compute distance.
+                let distance = {
+                    // The subtraction is always done in `isize` to enforce
+                    // the "no more than `isize::MAX` apart" requirement.
+                    let a_offset = ImmTy::from_uint(a_offset, isize_layout);
+                    let b_offset = ImmTy::from_uint(b_offset, isize_layout);
+                    let (val, overflowed, _ty) =
+                        self.overflowing_binary_op(BinOp::Sub, &a_offset, &b_offset)?;
+                    if overflowed {
+                        throw_ub_format!("pointers were too far apart for {}", intrinsic_name);
                     }
+                    val.to_machine_isize(self)?
+                };
+
+                // Check that the range between them is dereferenceable ("in-bounds or one past the
+                // end of the same allocation"). This is like the check in ptr_offset_inbounds.
+                let min_ptr = if distance >= 0 { b } else { a };
+                self.check_ptr_access_align(
+                    min_ptr,
+                    Size::from_bytes(distance.unsigned_abs()),
+                    Align::ONE,
+                    CheckInAllocMsg::OffsetFromTest,
+                )?;
+
+                if intrinsic_name == sym::ptr_offset_from_unsigned && distance < 0 {
+                    throw_ub_format!(
+                        "{} called when first pointer has smaller offset than second: {} < {}",
+                        intrinsic_name,
+                        a_offset,
+                        b_offset,
+                    );
                 }
+
+                // Perform division by size to compute return value.
+                let ret_layout = if intrinsic_name == sym::ptr_offset_from_unsigned {
+                    usize_layout
+                } else {
+                    isize_layout
+                };
+                let pointee_layout = self.layout_of(substs.type_at(0))?;
+                // If ret_layout is unsigned, we checked that so is the distance, so we are good.
+                let val = ImmTy::from_int(distance, ret_layout);
+                let size = ImmTy::from_int(pointee_layout.size.bytes(), ret_layout);
+                self.exact_div(&val, &size, dest)?;
             }
 
             sym::transmute => {
@@ -407,7 +412,11 @@
                     )?;
                 }
                 if intrinsic_name == sym::assert_zero_valid
-                    && !layout.might_permit_raw_init(self, /*zero:*/ true)
+                    && !layout.might_permit_raw_init(
+                        self,
+                        InitKind::Zero,
+                        self.tcx.sess.opts.debugging_opts.strict_init_checks,
+                    )
                 {
                     M::abort(
                         self,
@@ -418,7 +427,11 @@
                     )?;
                 }
                 if intrinsic_name == sym::assert_uninit_valid
-                    && !layout.might_permit_raw_init(self, /*zero:*/ false)
+                    && !layout.might_permit_raw_init(
+                        self,
+                        InitKind::Uninit,
+                        self.tcx.sess.opts.debugging_opts.strict_init_checks,
+                    )
                 {
                     M::abort(
                         self,
@@ -566,11 +579,10 @@
         // memory between these pointers must be accessible. Note that we do not require the
         // pointers to be properly aligned (unlike a read/write operation).
         let min_ptr = if offset_bytes >= 0 { ptr } else { offset_ptr };
-        let size = offset_bytes.unsigned_abs();
         // This call handles checking for integer/null pointers.
         self.check_ptr_access_align(
             min_ptr,
-            Size::from_bytes(size),
+            Size::from_bytes(offset_bytes.unsigned_abs()),
             Align::ONE,
             CheckInAllocMsg::PointerArithmeticTest,
         )?;
diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs b/compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs
index 5ece19d..23ae2db 100644
--- a/compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs
+++ b/compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs
@@ -15,7 +15,7 @@
 impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     /// Walks up the callstack from the intrinsic's callsite, searching for the first callsite in a
     /// frame which is not `#[track_caller]`.
-    crate fn find_closest_untracked_caller_location(&self) -> Span {
+    pub(crate) fn find_closest_untracked_caller_location(&self) -> Span {
         for frame in self.stack().iter().rev() {
             debug!("find_closest_untracked_caller_location: checking frame {:?}", frame.instance);
 
@@ -70,11 +70,11 @@
             }
         }
 
-        bug!("no non-`#[track_caller]` frame found")
+        span_bug!(self.cur_span(), "no non-`#[track_caller]` frame found")
     }
 
     /// Allocate a `const core::panic::Location` with the provided filename and line/column numbers.
-    crate fn alloc_caller_location(
+    pub(crate) fn alloc_caller_location(
         &mut self,
         filename: Symbol,
         line: u32,
@@ -113,7 +113,7 @@
         location
     }
 
-    crate fn location_triple_for_span(&self, span: Span) -> (Symbol, u32, u32) {
+    pub(crate) fn location_triple_for_span(&self, span: Span) -> (Symbol, u32, u32) {
         let topmost = span.ctxt().outer_expn().expansion_cause().unwrap_or(span);
         let caller = self.tcx.sess.source_map().lookup_char_pos(topmost.lo());
         (
diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics/type_name.rs b/compiler/rustc_const_eval/src/interpret/intrinsics/type_name.rs
index 447797f..f984774 100644
--- a/compiler/rustc_const_eval/src/interpret/intrinsics/type_name.rs
+++ b/compiler/rustc_const_eval/src/interpret/intrinsics/type_name.rs
@@ -189,7 +189,7 @@
 }
 
 /// Directly returns an `Allocation` containing an absolute path representation of the given type.
-crate fn alloc_type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> ConstAllocation<'tcx> {
+pub(crate) fn alloc_type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> ConstAllocation<'tcx> {
     let path = AbsolutePathPrinter { tcx, path: String::new() }.print_type(ty).unwrap().path;
     let alloc = Allocation::from_bytes_byte_aligned_immutable(path.into_bytes());
     tcx.intern_const_alloc(alloc)
diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs
index a79751c..080cabe 100644
--- a/compiler/rustc_const_eval/src/interpret/machine.rs
+++ b/compiler/rustc_const_eval/src/interpret/machine.rs
@@ -133,9 +133,11 @@
     /// Whether to enforce the validity invariant
     fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool;
 
-    /// Whether to enforce validity (e.g., initialization and not having ptr provenance)
-    /// of integers and floats.
-    fn enforce_number_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool;
+    /// Whether to enforce integers and floats being initialized.
+    fn enforce_number_init(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool;
+
+    /// Whether to enforce integers and floats not having provenance.
+    fn enforce_number_no_provenance(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool;
 
     /// Whether function calls should be [ABI](Abi)-checked.
     fn enforce_abi(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
@@ -167,7 +169,8 @@
         instance: ty::Instance<'tcx>,
         abi: Abi,
         args: &[OpTy<'tcx, Self::PointerTag>],
-        ret: Option<(&PlaceTy<'tcx, Self::PointerTag>, mir::BasicBlock)>,
+        destination: &PlaceTy<'tcx, Self::PointerTag>,
+        target: Option<mir::BasicBlock>,
         unwind: StackPopUnwind,
     ) -> InterpResult<'tcx, Option<(&'mir mir::Body<'tcx>, ty::Instance<'tcx>)>>;
 
@@ -178,7 +181,8 @@
         fn_val: Self::ExtraFnVal,
         abi: Abi,
         args: &[OpTy<'tcx, Self::PointerTag>],
-        ret: Option<(&PlaceTy<'tcx, Self::PointerTag>, mir::BasicBlock)>,
+        destination: &PlaceTy<'tcx, Self::PointerTag>,
+        target: Option<mir::BasicBlock>,
         unwind: StackPopUnwind,
     ) -> InterpResult<'tcx>;
 
@@ -188,7 +192,8 @@
         ecx: &mut InterpCx<'mir, 'tcx, Self>,
         instance: ty::Instance<'tcx>,
         args: &[OpTy<'tcx, Self::PointerTag>],
-        ret: Option<(&PlaceTy<'tcx, Self::PointerTag>, mir::BasicBlock)>,
+        destination: &PlaceTy<'tcx, Self::PointerTag>,
+        target: Option<mir::BasicBlock>,
         unwind: StackPopUnwind,
     ) -> InterpResult<'tcx>;
 
@@ -289,11 +294,10 @@
     fn ptr_from_addr_cast(
         ecx: &InterpCx<'mir, 'tcx, Self>,
         addr: u64,
-    ) -> Pointer<Option<Self::PointerTag>>;
+    ) -> InterpResult<'tcx, Pointer<Option<Self::PointerTag>>>;
 
-    // FIXME: Transmuting an integer to a pointer should just always return a `None`
-    // provenance, but that causes problems with function pointers in Miri.
     /// Hook for returning a pointer from a transmute-like operation on an addr.
+    /// This is only needed to support Miri's (unsound) "allow-ptr-int-transmute" flag.
     fn ptr_from_addr_transmute(
         ecx: &InterpCx<'mir, 'tcx, Self>,
         addr: u64,
@@ -330,12 +334,14 @@
     /// allocation (because a copy had to be done to add tags or metadata), machine memory will
     /// cache the result. (This relies on `AllocMap::get_or` being able to add the
     /// owned allocation to the map even when the map is shared.)
+    ///
+    /// This must only fail if `alloc` contains relocations.
     fn init_allocation_extra<'b>(
         ecx: &InterpCx<'mir, 'tcx, Self>,
         id: AllocId,
         alloc: Cow<'b, Allocation>,
         kind: Option<MemoryKind<Self::MemoryKind>>,
-    ) -> Cow<'b, Allocation<Self::PointerTag, Self::AllocExtra>>;
+    ) -> InterpResult<'tcx, Cow<'b, Allocation<Self::PointerTag, Self::AllocExtra>>>;
 
     /// Hook for performing extra checks on a memory read access.
     ///
@@ -453,17 +459,23 @@
     }
 
     #[inline(always)]
-    fn enforce_number_validity(_ecx: &InterpCx<$mir, $tcx, Self>) -> bool {
+    fn enforce_number_init(_ecx: &InterpCx<$mir, $tcx, Self>) -> bool {
         true
     }
 
     #[inline(always)]
+    fn enforce_number_no_provenance(_ecx: &InterpCx<$mir, $tcx, Self>) -> bool {
+        false
+    }
+
+    #[inline(always)]
     fn call_extra_fn(
         _ecx: &mut InterpCx<$mir, $tcx, Self>,
         fn_val: !,
         _abi: Abi,
         _args: &[OpTy<$tcx>],
-        _ret: Option<(&PlaceTy<$tcx>, mir::BasicBlock)>,
+        _destination: &PlaceTy<$tcx, Self::PointerTag>,
+        _target: Option<mir::BasicBlock>,
         _unwind: StackPopUnwind,
     ) -> InterpResult<$tcx> {
         match fn_val {}
@@ -475,9 +487,9 @@
         _id: AllocId,
         alloc: Cow<'b, Allocation>,
         _kind: Option<MemoryKind<Self::MemoryKind>>,
-    ) -> Cow<'b, Allocation<Self::PointerTag>> {
+    ) -> InterpResult<$tcx, Cow<'b, Allocation<Self::PointerTag>>> {
         // We do not use a tag so we can just cheaply forward the allocation
-        alloc
+        Ok(alloc)
     }
 
     fn extern_static_base_pointer(
@@ -508,8 +520,10 @@
     fn ptr_from_addr_cast(
         _ecx: &InterpCx<$mir, $tcx, Self>,
         addr: u64,
-    ) -> Pointer<Option<AllocId>> {
-        Pointer::new(None, Size::from_bytes(addr))
+    ) -> InterpResult<$tcx, Pointer<Option<AllocId>>> {
+        // Allow these casts, but make the pointer not dereferenceable.
+        // (I.e., they behave like transmutation.)
+        Ok(Pointer::new(None, Size::from_bytes(addr)))
     }
 
     #[inline(always)]
diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs
index 33162a0..d46f2f3 100644
--- a/compiler/rustc_const_eval/src/interpret/memory.rs
+++ b/compiler/rustc_const_eval/src/interpret/memory.rs
@@ -197,9 +197,10 @@
         size: Size,
         align: Align,
         kind: MemoryKind<M::MemoryKind>,
-    ) -> InterpResult<'static, Pointer<M::PointerTag>> {
+    ) -> InterpResult<'tcx, Pointer<M::PointerTag>> {
         let alloc = Allocation::uninit(size, align, M::PANIC_ON_ALLOC_FAIL)?;
-        Ok(self.allocate_raw_ptr(alloc, kind))
+        // We can `unwrap` since `alloc` contains no pointers.
+        Ok(self.allocate_raw_ptr(alloc, kind).unwrap())
     }
 
     pub fn allocate_bytes_ptr(
@@ -210,23 +211,25 @@
         mutability: Mutability,
     ) -> Pointer<M::PointerTag> {
         let alloc = Allocation::from_bytes(bytes, align, mutability);
-        self.allocate_raw_ptr(alloc, kind)
+        // We can `unwrap` since `alloc` contains no pointers.
+        self.allocate_raw_ptr(alloc, kind).unwrap()
     }
 
+    /// This can fail only of `alloc` contains relocations.
     pub fn allocate_raw_ptr(
         &mut self,
         alloc: Allocation,
         kind: MemoryKind<M::MemoryKind>,
-    ) -> Pointer<M::PointerTag> {
+    ) -> InterpResult<'tcx, Pointer<M::PointerTag>> {
         let id = self.tcx.reserve_alloc_id();
         debug_assert_ne!(
             Some(kind),
             M::GLOBAL_KIND.map(MemoryKind::Machine),
             "dynamically allocating global memory"
         );
-        let alloc = M::init_allocation_extra(self, id, Cow::Owned(alloc), Some(kind));
+        let alloc = M::init_allocation_extra(self, id, Cow::Owned(alloc), Some(kind))?;
         self.memory.alloc_map.insert(id, (kind, alloc.into_owned()));
-        M::tag_alloc_base_pointer(self, Pointer::from(id))
+        Ok(M::tag_alloc_base_pointer(self, Pointer::from(id)))
     }
 
     pub fn reallocate_ptr(
@@ -402,7 +405,7 @@
         msg: CheckInAllocMsg,
         alloc_size: impl FnOnce(AllocId, Size, M::TagExtra) -> InterpResult<'tcx, (Size, Align, T)>,
     ) -> InterpResult<'tcx, Option<T>> {
-        fn check_offset_align(offset: u64, align: Align) -> InterpResult<'static> {
+        fn check_offset_align<'tcx>(offset: u64, align: Align) -> InterpResult<'tcx> {
             if offset % align.bytes() == 0 {
                 Ok(())
             } else {
@@ -441,6 +444,10 @@
                         msg,
                     })
                 }
+                // Ensure we never consider the null pointer dereferencable.
+                if M::PointerTag::OFFSET_IS_ADDR {
+                    assert_ne!(ptr.addr(), Size::ZERO);
+                }
                 // Test align. Check this last; if both bounds and alignment are violated
                 // we want the error to be about the bounds.
                 if let Some(align) = align {
@@ -500,18 +507,18 @@
                     throw_unsup!(ReadExternStatic(def_id));
                 }
 
-                (self.tcx.eval_static_initializer(def_id)?, Some(def_id))
+                // Use a precise span for better cycle errors.
+                (self.tcx.at(self.cur_span()).eval_static_initializer(def_id)?, Some(def_id))
             }
         };
         M::before_access_global(*self.tcx, &self.machine, id, alloc, def_id, is_write)?;
         // We got tcx memory. Let the machine initialize its "extra" stuff.
-        let alloc = M::init_allocation_extra(
+        M::init_allocation_extra(
             self,
             id, // always use the ID we got as input, not the "hidden" one.
             Cow::Borrowed(alloc.inner()),
             M::GLOBAL_KIND.map(MemoryKind::Machine),
-        );
-        Ok(alloc)
+        )
     }
 
     /// Gives raw access to the `Allocation`, without bounds or alignment checks.
@@ -654,7 +661,7 @@
         &self,
         id: AllocId,
         liveness: AllocCheck,
-    ) -> InterpResult<'static, (Size, Align)> {
+    ) -> InterpResult<'tcx, (Size, Align)> {
         // # Regular allocations
         // Don't use `self.get_raw` here as that will
         // a) cause cycles in case `id` refers to a static
@@ -904,11 +911,15 @@
 }
 
 impl<'tcx, 'a, Tag: Provenance, Extra> AllocRef<'a, 'tcx, Tag, Extra> {
-    pub fn read_scalar(&self, range: AllocRange) -> InterpResult<'tcx, ScalarMaybeUninit<Tag>> {
+    pub fn read_scalar(
+        &self,
+        range: AllocRange,
+        read_provenance: bool,
+    ) -> InterpResult<'tcx, ScalarMaybeUninit<Tag>> {
         let range = self.range.subrange(range);
         let res = self
             .alloc
-            .read_scalar(&self.tcx, range)
+            .read_scalar(&self.tcx, range, read_provenance)
             .map_err(|e| e.to_interp_error(self.alloc_id))?;
         debug!(
             "read_scalar in {} at {:#x}, size {}: {:?}",
@@ -920,14 +931,30 @@
         Ok(res)
     }
 
-    pub fn read_ptr_sized(&self, offset: Size) -> InterpResult<'tcx, ScalarMaybeUninit<Tag>> {
-        self.read_scalar(alloc_range(offset, self.tcx.data_layout().pointer_size))
+    pub fn read_integer(
+        &self,
+        offset: Size,
+        size: Size,
+    ) -> InterpResult<'tcx, ScalarMaybeUninit<Tag>> {
+        self.read_scalar(alloc_range(offset, size), /*read_provenance*/ false)
     }
 
-    pub fn check_bytes(&self, range: AllocRange, allow_uninit_and_ptr: bool) -> InterpResult<'tcx> {
+    pub fn read_pointer(&self, offset: Size) -> InterpResult<'tcx, ScalarMaybeUninit<Tag>> {
+        self.read_scalar(
+            alloc_range(offset, self.tcx.data_layout().pointer_size),
+            /*read_provenance*/ true,
+        )
+    }
+
+    pub fn check_bytes(
+        &self,
+        range: AllocRange,
+        allow_uninit: bool,
+        allow_ptr: bool,
+    ) -> InterpResult<'tcx> {
         Ok(self
             .alloc
-            .check_bytes(&self.tcx, self.range.subrange(range), allow_uninit_and_ptr)
+            .check_bytes(&self.tcx, self.range.subrange(range), allow_uninit, allow_ptr)
             .map_err(|e| e.to_interp_error(self.alloc_id))?)
     }
 }
@@ -1144,11 +1171,7 @@
                 Err(ptr) => ptr.into(),
                 Ok(bits) => {
                     let addr = u64::try_from(bits).unwrap();
-                    let ptr = M::ptr_from_addr_transmute(&self, addr);
-                    if addr == 0 {
-                        assert!(ptr.provenance.is_none(), "null pointer can never have an AllocId");
-                    }
-                    ptr
+                    M::ptr_from_addr_transmute(&self, addr)
                 }
             },
         )
diff --git a/compiler/rustc_const_eval/src/interpret/mod.rs b/compiler/rustc_const_eval/src/interpret/mod.rs
index 69d6c84..2b73ad5 100644
--- a/compiler/rustc_const_eval/src/interpret/mod.rs
+++ b/compiler/rustc_const_eval/src/interpret/mod.rs
@@ -29,5 +29,5 @@
 pub use self::validity::{CtfeValidationMode, RefTracking};
 pub use self::visitor::{MutValueVisitor, Value, ValueVisitor};
 
-crate use self::intrinsics::eval_nullary_intrinsic;
+pub(crate) use self::intrinsics::eval_nullary_intrinsic;
 use eval_context::{from_known_layout, mir_assign_valid_types};
diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs
index 5c85c86..6b05a49 100644
--- a/compiler/rustc_const_eval/src/interpret/operand.rs
+++ b/compiler/rustc_const_eval/src/interpret/operand.rs
@@ -15,8 +15,8 @@
 
 use super::{
     alloc_range, from_known_layout, mir_assign_valid_types, AllocId, ConstValue, GlobalId,
-    InterpCx, InterpResult, MPlaceTy, Machine, MemPlace, Place, PlaceTy, Pointer, Provenance,
-    Scalar, ScalarMaybeUninit,
+    InterpCx, InterpResult, MPlaceTy, Machine, MemPlace, Place, PlaceTy, Pointer,
+    PointerArithmetic, Provenance, Scalar, ScalarMaybeUninit,
 };
 
 /// An `Immediate` represents a single immediate self-contained Rust value.
@@ -284,11 +284,18 @@
             Abi::Scalar(s) if force => Some(s.primitive()),
             _ => None,
         };
-        if let Some(_s) = scalar_layout {
+        let read_provenance = |s: abi::Primitive, size| {
+            // Should be just `s.is_ptr()`, but we support a Miri flag that accepts more
+            // questionable ptr-int transmutes.
+            let number_may_have_provenance = !M::enforce_number_no_provenance(self);
+            s.is_ptr() || (number_may_have_provenance && size == self.pointer_size())
+        };
+        if let Some(s) = scalar_layout {
             //FIXME(#96185): let size = s.size(self);
             //FIXME(#96185): assert_eq!(size, mplace.layout.size, "abi::Scalar size does not match layout size");
             let size = mplace.layout.size; //FIXME(#96185): remove this line
-            let scalar = alloc.read_scalar(alloc_range(Size::ZERO, size))?;
+            let scalar =
+                alloc.read_scalar(alloc_range(Size::ZERO, size), read_provenance(s, size))?;
             return Ok(Some(ImmTy { imm: scalar.into(), layout: mplace.layout }));
         }
         let scalar_pair_layout = match mplace.layout.abi {
@@ -306,8 +313,10 @@
             let (a_size, b_size) = (a.size(self), b.size(self));
             let b_offset = a_size.align_to(b.align(self).abi);
             assert!(b_offset.bytes() > 0); // in `operand_field` we use the offset to tell apart the fields
-            let a_val = alloc.read_scalar(alloc_range(Size::ZERO, a_size))?;
-            let b_val = alloc.read_scalar(alloc_range(b_offset, b_size))?;
+            let a_val =
+                alloc.read_scalar(alloc_range(Size::ZERO, a_size), read_provenance(a, a_size))?;
+            let b_val =
+                alloc.read_scalar(alloc_range(b_offset, b_size), read_provenance(b, b_size))?;
             return Ok(Some(ImmTy {
                 imm: Immediate::ScalarPair(a_val, b_val),
                 layout: mplace.layout,
@@ -613,10 +622,10 @@
     /// "universe" (param_env).
     pub fn const_to_op(
         &self,
-        val: ty::Const<'tcx>,
+        c: ty::Const<'tcx>,
         layout: Option<TyAndLayout<'tcx>>,
     ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
-        match val.val() {
+        match c.kind() {
             ty::ConstKind::Param(_) | ty::ConstKind::Bound(..) => throw_inval!(TooGeneric),
             ty::ConstKind::Error(DelaySpanBugEmitted { reported, .. }) => {
                 throw_inval!(AlreadyReported(reported))
@@ -626,9 +635,13 @@
                 Ok(self.eval_to_allocation(GlobalId { instance, promoted: uv.promoted })?.into())
             }
             ty::ConstKind::Infer(..) | ty::ConstKind::Placeholder(..) => {
-                span_bug!(self.cur_span(), "const_to_op: Unexpected ConstKind {:?}", val)
+                span_bug!(self.cur_span(), "const_to_op: Unexpected ConstKind {:?}", c)
             }
-            ty::ConstKind::Value(val_val) => self.const_val_to_op(val_val, val.ty(), layout),
+            ty::ConstKind::Value(valtree) => {
+                let ty = c.ty();
+                let const_val = self.tcx.valtree_to_const_val((ty, valtree));
+                self.const_val_to_op(const_val, ty, layout)
+            }
         }
     }
 
@@ -643,7 +656,7 @@
         }
     }
 
-    crate fn const_val_to_op(
+    pub(crate) fn const_val_to_op(
         &self,
         val_val: ConstValue<'tcx>,
         ty: Ty<'tcx>,
diff --git a/compiler/rustc_const_eval/src/interpret/operator.rs b/compiler/rustc_const_eval/src/interpret/operator.rs
index 6dae9dc..85ee88e 100644
--- a/compiler/rustc_const_eval/src/interpret/operator.rs
+++ b/compiler/rustc_const_eval/src/interpret/operator.rs
@@ -154,14 +154,14 @@
                 let result = match bin_op {
                     Shl => l.checked_shl(r).unwrap(),
                     Shr => l.checked_shr(r).unwrap(),
-                    _ => bug!("it has already been checked that this is a shift op"),
+                    _ => bug!(),
                 };
                 result as u128
             } else {
                 match bin_op {
                     Shl => l.checked_shl(r).unwrap(),
                     Shr => l.checked_shr(r).unwrap(),
-                    _ => bug!("it has already been checked that this is a shift op"),
+                    _ => bug!(),
                 }
             };
             let truncated = self.truncate(result, left_layout);
diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs
index 95d6f43..3dbcba7 100644
--- a/compiler/rustc_const_eval/src/interpret/place.rs
+++ b/compiler/rustc_const_eval/src/interpret/place.rs
@@ -115,12 +115,6 @@
     }
 }
 
-impl<'tcx, Tag: Provenance> std::ops::DerefMut for MPlaceTy<'tcx, Tag> {
-    fn deref_mut(&mut self) -> &mut Self::Target {
-        &mut self.mplace
-    }
-}
-
 impl<'tcx, Tag: Provenance> From<MPlaceTy<'tcx, Tag>> for PlaceTy<'tcx, Tag> {
     #[inline(always)]
     fn from(mplace: MPlaceTy<'tcx, Tag>) -> Self {
@@ -197,6 +191,18 @@
     }
 
     #[inline]
+    pub fn from_aligned_ptr_with_meta(
+        ptr: Pointer<Option<Tag>>,
+        layout: TyAndLayout<'tcx>,
+        meta: MemPlaceMeta<Tag>,
+    ) -> Self {
+        let mut mplace = MemPlace::from_ptr(ptr, layout.align.abi);
+        mplace.meta = meta;
+
+        MPlaceTy { mplace, layout }
+    }
+
+    #[inline]
     pub(crate) fn len(&self, cx: &impl HasDataLayout) -> InterpResult<'tcx, u64> {
         if self.layout.is_unsized() {
             // We need to consult `meta` metadata
@@ -307,6 +313,11 @@
     ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
         let val = self.read_immediate(src)?;
         trace!("deref to {} on {:?}", val.layout.ty, *val);
+
+        if val.layout.ty.is_box() {
+            bug!("dereferencing {:?}", val.layout.ty);
+        }
+
         let mplace = self.ref_to_mplace(&val)?;
         self.check_mplace_access(mplace, CheckInAllocMsg::DerefTest)?;
         Ok(mplace)
@@ -495,7 +506,7 @@
 
     /// Project into an mplace
     #[instrument(skip(self), level = "debug")]
-    pub(crate) fn mplace_projection(
+    pub(super) fn mplace_projection(
         &self,
         base: &MPlaceTy<'tcx, M::PointerTag>,
         proj_elem: mir::PlaceElem<'tcx>,
@@ -863,8 +874,6 @@
             Ok(src_val) => {
                 assert!(!src.layout.is_unsized(), "cannot have unsized immediates");
                 // Yay, we got a value that we can write directly.
-                // FIXME: Add a check to make sure that if `src` is indirect,
-                // it does not overlap with `dest`.
                 return self.write_immediate_no_validate(*src_val, dest);
             }
             Err(mplace) => mplace,
@@ -884,7 +893,7 @@
         });
         assert_eq!(src.meta, dest.meta, "Can only copy between equally-sized instances");
 
-        self.mem_copy(src.ptr, src.align, dest.ptr, dest.align, size, /*nonoverlapping*/ true)
+        self.mem_copy(src.ptr, src.align, dest.ptr, dest.align, size, /*nonoverlapping*/ false)
     }
 
     /// Copies the data from an operand to a place. The layouts may disagree, but they must
@@ -900,16 +909,12 @@
         }
         // We still require the sizes to match.
         if src.layout.size != dest.layout.size {
-            // FIXME: This should be an assert instead of an error, but if we transmute within an
-            // array length computation, `typeck` may not have yet been run and errored out. In fact
-            // most likely we *are* running `typeck` right now. Investigate whether we can bail out
-            // on `typeck_results().has_errors` at all const eval entry points.
-            debug!("Size mismatch when transmuting!\nsrc: {:#?}\ndest: {:#?}", src, dest);
-            self.tcx.sess.delay_span_bug(
+            span_bug!(
                 self.cur_span(),
-                "size-changing transmute, should have been caught by transmute checking",
+                "size-changing transmute, should have been caught by transmute checking: {:#?}\ndest: {:#?}",
+                src,
+                dest
             );
-            throw_inval!(TransmuteSizeDiff(src.layout.ty, dest.layout.ty));
         }
         // Unsized copies rely on interpreting `src.meta` with `dest.layout`, we want
         // to avoid that here.
@@ -1005,7 +1010,7 @@
         &mut self,
         layout: TyAndLayout<'tcx>,
         kind: MemoryKind<M::MemoryKind>,
-    ) -> InterpResult<'static, MPlaceTy<'tcx, M::PointerTag>> {
+    ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
         let ptr = self.allocate_ptr(layout.size, layout.align.abi, kind)?;
         Ok(MPlaceTy::from_aligned_ptr(ptr.into(), layout))
     }
diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs
index e6dfdf5..98f6945 100644
--- a/compiler/rustc_const_eval/src/interpret/step.rs
+++ b/compiler/rustc_const_eval/src/interpret/step.rs
@@ -55,33 +55,32 @@
         };
         let basic_block = &self.body().basic_blocks()[loc.block];
 
-        let old_frames = self.frame_idx();
-
         if let Some(stmt) = basic_block.statements.get(loc.statement_index) {
-            assert_eq!(old_frames, self.frame_idx());
+            let old_frames = self.frame_idx();
             self.statement(stmt)?;
+            // Make sure we are not updating `statement_index` of the wrong frame.
+            assert_eq!(old_frames, self.frame_idx());
+            // Advance the program counter.
+            self.frame_mut().loc.as_mut().unwrap().statement_index += 1;
             return Ok(true);
         }
 
         M::before_terminator(self)?;
 
         let terminator = basic_block.terminator();
-        assert_eq!(old_frames, self.frame_idx());
         self.terminator(terminator)?;
         Ok(true)
     }
 
     /// Runs the interpretation logic for the given `mir::Statement` at the current frame and
-    /// statement counter. This also moves the statement counter forward.
+    /// statement counter.
+    ///
+    /// This does NOT move the statement counter forward, the caller has to do that!
     pub fn statement(&mut self, stmt: &mir::Statement<'tcx>) -> InterpResult<'tcx> {
         info!("{:?}", stmt);
 
         use rustc_middle::mir::StatementKind::*;
 
-        // Some statements (e.g., box) push new stack frames.
-        // We have to record the stack frame number *before* executing the statement.
-        let frame_idx = self.frame_idx();
-
         match &stmt.kind {
             Assign(box (place, rvalue)) => self.eval_rvalue_into_place(rvalue, *place)?,
 
@@ -144,7 +143,6 @@
             Nop => {}
         }
 
-        self.stack_mut()[frame_idx].loc.as_mut().unwrap().statement_index += 1;
         Ok(())
     }
 
@@ -158,6 +156,8 @@
         place: mir::Place<'tcx>,
     ) -> InterpResult<'tcx> {
         let dest = self.eval_place(place)?;
+        // FIXME: ensure some kind of non-aliasing between LHS and RHS?
+        // Also see https://github.com/rust-lang/rust/issues/68364.
 
         use rustc_middle::mir::Rvalue::*;
         match *rvalue {
@@ -298,6 +298,7 @@
         Ok(())
     }
 
+    /// Evaluate the given terminator. Will also adjust the stack frame and statement position accordingly.
     fn terminator(&mut self, terminator: &mir::Terminator<'tcx>) -> InterpResult<'tcx> {
         info!("{:?}", terminator.kind);
 
diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs
index c266456..57d06b4 100644
--- a/compiler/rustc_const_eval/src/interpret/terminator.rs
+++ b/compiler/rustc_const_eval/src/interpret/terminator.rs
@@ -57,7 +57,15 @@
                 self.go_to_block(target_block);
             }
 
-            Call { ref func, ref args, destination, ref cleanup, from_hir_call: _, fn_span: _ } => {
+            Call {
+                ref func,
+                ref args,
+                destination,
+                target,
+                ref cleanup,
+                from_hir_call: _,
+                fn_span: _,
+            } => {
                 let old_stack = self.frame_idx();
                 let old_loc = self.frame().loc;
                 let func = self.eval_operand(func, None)?;
@@ -91,20 +99,14 @@
                     ),
                 };
 
-                let dest_place;
-                let ret = match destination {
-                    Some((dest, ret)) => {
-                        dest_place = self.eval_place(dest)?;
-                        Some((&dest_place, ret))
-                    }
-                    None => None,
-                };
+                let destination = self.eval_place(destination)?;
                 self.eval_fn_call(
                     fn_val,
                     (fn_sig.abi, fn_abi),
                     &args,
                     with_caller_location,
-                    ret,
+                    &destination,
+                    target,
                     match (cleanup, fn_abi.can_unwind) {
                         (Some(cleanup), true) => StackPopUnwind::Cleanup(*cleanup),
                         (None, true) => StackPopUnwind::Skip,
@@ -183,7 +185,14 @@
                 // No question
                 return true;
             }
-            // Compare layout
+            if caller_abi.layout.size != callee_abi.layout.size
+                || caller_abi.layout.align.abi != callee_abi.layout.align.abi
+            {
+                // This cannot go well...
+                // FIXME: What about unsized types?
+                return false;
+            }
+            // The rest *should* be okay, but we are extra conservative.
             match (caller_abi.layout.abi, callee_abi.layout.abi) {
                 // Different valid ranges are okay (once we enforce validity,
                 // that will take care to make it UB to leave the range, just
@@ -299,7 +308,8 @@
         (caller_abi, caller_fn_abi): (Abi, &FnAbi<'tcx, Ty<'tcx>>),
         args: &[OpTy<'tcx, M::PointerTag>],
         with_caller_location: bool,
-        ret: Option<(&PlaceTy<'tcx, M::PointerTag>, mir::BasicBlock)>,
+        destination: &PlaceTy<'tcx, M::PointerTag>,
+        target: Option<mir::BasicBlock>,
         mut unwind: StackPopUnwind,
     ) -> InterpResult<'tcx> {
         trace!("eval_fn_call: {:#?}", fn_val);
@@ -307,15 +317,23 @@
         let instance = match fn_val {
             FnVal::Instance(instance) => instance,
             FnVal::Other(extra) => {
-                return M::call_extra_fn(self, extra, caller_abi, args, ret, unwind);
+                return M::call_extra_fn(
+                    self,
+                    extra,
+                    caller_abi,
+                    args,
+                    destination,
+                    target,
+                    unwind,
+                );
             }
         };
 
         match instance.def {
-            ty::InstanceDef::Intrinsic(..) => {
-                assert!(caller_abi == Abi::RustIntrinsic || caller_abi == Abi::PlatformIntrinsic);
+            ty::InstanceDef::Intrinsic(def_id) => {
+                assert!(self.tcx.is_intrinsic(def_id));
                 // caller_fn_abi is not relevant here, we interpret the arguments directly for each intrinsic.
-                M::call_intrinsic(self, instance, args, ret, unwind)
+                M::call_intrinsic(self, instance, args, destination, target, unwind)
             }
             ty::InstanceDef::VtableShim(..)
             | ty::InstanceDef::ReifyShim(..)
@@ -326,7 +344,7 @@
             | ty::InstanceDef::Item(_) => {
                 // We need MIR for this fn
                 let Some((body, instance)) =
-                    M::find_mir_or_eval_fn(self, instance, caller_abi, args, ret, unwind)? else {
+                    M::find_mir_or_eval_fn(self, instance, caller_abi, args, destination, target, unwind)? else {
                         return Ok(());
                     };
 
@@ -335,12 +353,7 @@
                 // FIXME: for variadic support, do we have to somehow determine callee's extra_args?
                 let callee_fn_abi = self.fn_abi_of_instance(instance, ty::List::empty())?;
 
-                if callee_fn_abi.c_variadic != caller_fn_abi.c_variadic {
-                    throw_ub_format!(
-                        "calling a c-variadic function via a non-variadic call site, or vice versa"
-                    );
-                }
-                if callee_fn_abi.c_variadic {
+                if callee_fn_abi.c_variadic || caller_fn_abi.c_variadic {
                     throw_unsup_format!("calling a c-variadic function is not supported");
                 }
 
@@ -362,8 +375,8 @@
                 self.push_stack_frame(
                     instance,
                     body,
-                    ret.map(|p| p.0),
-                    StackPopCleanup::Goto { ret: ret.map(|p| p.1), unwind },
+                    destination,
+                    StackPopCleanup::Goto { ret: target, unwind },
                 )?;
 
                 // If an error is raised here, pop the frame again to get an accurate backtrace.
@@ -540,7 +553,8 @@
                     (caller_abi, caller_fn_abi),
                     &args,
                     with_caller_location,
-                    ret,
+                    destination,
+                    target,
                     unwind,
                 )
             }
@@ -582,7 +596,8 @@
             (Abi::Rust, fn_abi),
             &[arg.into()],
             false,
-            Some((&dest.into(), target)),
+            &dest.into(),
+            Some(target),
             match unwind {
                 Some(cleanup) => StackPopUnwind::Cleanup(cleanup),
                 None => StackPopUnwind::Skip,
diff --git a/compiler/rustc_const_eval/src/interpret/traits.rs b/compiler/rustc_const_eval/src/interpret/traits.rs
index 2359384..9c48f3e 100644
--- a/compiler/rustc_const_eval/src/interpret/traits.rs
+++ b/compiler/rustc_const_eval/src/interpret/traits.rs
@@ -2,8 +2,8 @@
 
 use rustc_middle::mir::interpret::{InterpResult, Pointer, PointerArithmetic};
 use rustc_middle::ty::{
-    self, Ty, COMMON_VTABLE_ENTRIES, COMMON_VTABLE_ENTRIES_ALIGN,
-    COMMON_VTABLE_ENTRIES_DROPINPLACE, COMMON_VTABLE_ENTRIES_SIZE,
+    self, Ty, TyCtxt, COMMON_VTABLE_ENTRIES_ALIGN, COMMON_VTABLE_ENTRIES_DROPINPLACE,
+    COMMON_VTABLE_ENTRIES_SIZE,
 };
 use rustc_target::abi::{Align, Size};
 
@@ -38,7 +38,7 @@
     }
 
     /// Resolves the function at the specified slot in the provided
-    /// vtable. Currently an index of '3' (`COMMON_VTABLE_ENTRIES.len()`)
+    /// vtable. Currently an index of '3' (`TyCtxt::COMMON_VTABLE_ENTRIES.len()`)
     /// corresponds to the first method declared in the trait of the provided vtable.
     pub fn get_vtable_slot(
         &self,
@@ -50,7 +50,7 @@
         let vtable_slot = self
             .get_ptr_alloc(vtable_slot, ptr_size, self.tcx.data_layout.pointer_align.abi)?
             .expect("cannot be a ZST");
-        let fn_ptr = self.scalar_to_ptr(vtable_slot.read_ptr_sized(Size::ZERO)?.check_init()?)?;
+        let fn_ptr = self.scalar_to_ptr(vtable_slot.read_pointer(Size::ZERO)?.check_init()?)?;
         self.get_ptr_fn(fn_ptr)
     }
 
@@ -64,14 +64,12 @@
         let vtable = self
             .get_ptr_alloc(
                 vtable,
-                pointer_size * u64::try_from(COMMON_VTABLE_ENTRIES.len()).unwrap(),
+                pointer_size * u64::try_from(TyCtxt::COMMON_VTABLE_ENTRIES.len()).unwrap(),
                 self.tcx.data_layout.pointer_align.abi,
             )?
             .expect("cannot be a ZST");
         let drop_fn = vtable
-            .read_ptr_sized(
-                pointer_size * u64::try_from(COMMON_VTABLE_ENTRIES_DROPINPLACE).unwrap(),
-            )?
+            .read_pointer(pointer_size * u64::try_from(COMMON_VTABLE_ENTRIES_DROPINPLACE).unwrap())?
             .check_init()?;
         // We *need* an instance here, no other kind of function value, to be able
         // to determine the type.
@@ -99,17 +97,23 @@
         let vtable = self
             .get_ptr_alloc(
                 vtable,
-                pointer_size * u64::try_from(COMMON_VTABLE_ENTRIES.len()).unwrap(),
+                pointer_size * u64::try_from(TyCtxt::COMMON_VTABLE_ENTRIES.len()).unwrap(),
                 self.tcx.data_layout.pointer_align.abi,
             )?
             .expect("cannot be a ZST");
         let size = vtable
-            .read_ptr_sized(pointer_size * u64::try_from(COMMON_VTABLE_ENTRIES_SIZE).unwrap())?
+            .read_integer(
+                pointer_size * u64::try_from(COMMON_VTABLE_ENTRIES_SIZE).unwrap(),
+                pointer_size,
+            )?
             .check_init()?;
         let size = size.to_machine_usize(self)?;
         let size = Size::from_bytes(size);
         let align = vtable
-            .read_ptr_sized(pointer_size * u64::try_from(COMMON_VTABLE_ENTRIES_ALIGN).unwrap())?
+            .read_integer(
+                pointer_size * u64::try_from(COMMON_VTABLE_ENTRIES_ALIGN).unwrap(),
+                pointer_size,
+            )?
             .check_init()?;
         let align = align.to_machine_usize(self)?;
         let align = Align::from_bytes(align).map_err(|e| err_ub!(InvalidVtableAlignment(e)))?;
@@ -132,8 +136,7 @@
             .get_ptr_alloc(vtable_slot, pointer_size, self.tcx.data_layout.pointer_align.abi)?
             .expect("cannot be a ZST");
 
-        let new_vtable =
-            self.scalar_to_ptr(new_vtable.read_ptr_sized(Size::ZERO)?.check_init()?)?;
+        let new_vtable = self.scalar_to_ptr(new_vtable.read_pointer(Size::ZERO)?.check_init()?)?;
 
         Ok(new_vtable)
     }
diff --git a/compiler/rustc_const_eval/src/interpret/util.rs b/compiler/rustc_const_eval/src/interpret/util.rs
index e17bd9a..b986699 100644
--- a/compiler/rustc_const_eval/src/interpret/util.rs
+++ b/compiler/rustc_const_eval/src/interpret/util.rs
@@ -1,5 +1,5 @@
 use rustc_middle::mir::interpret::InterpResult;
-use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeVisitor};
+use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable, TypeVisitor};
 use std::convert::TryInto;
 use std::ops::ControlFlow;
 
@@ -8,7 +8,7 @@
 /// In case it does, returns a `TooGeneric` const eval error. Note that due to polymorphization
 /// types may be "concrete enough" even though they still contain generic parameters in
 /// case these parameters are unused.
-crate fn ensure_monomorphic_enough<'tcx, T>(tcx: TyCtxt<'tcx>, ty: T) -> InterpResult<'tcx>
+pub(crate) fn ensure_monomorphic_enough<'tcx, T>(tcx: TyCtxt<'tcx>, ty: T) -> InterpResult<'tcx>
 where
     T: TypeFoldable<'tcx>,
 {
@@ -47,7 +47,7 @@
                         match (is_used, subst.needs_subst()) {
                             // Just in case there are closures or generators within this subst,
                             // recurse.
-                            (true, true) => return subst.super_visit_with(self),
+                            (true, true) => return subst.visit_with(self),
                             // Confirm that polymorphization replaced the parameter with
                             // `ty::Param`/`ty::ConstKind::Param`.
                             (false, true) if cfg!(debug_assertions) => match subst.unpack() {
@@ -55,7 +55,7 @@
                                     assert!(matches!(ty.kind(), ty::Param(_)))
                                 }
                                 ty::subst::GenericArgKind::Const(ct) => {
-                                    assert!(matches!(ct.val(), ty::ConstKind::Param(_)))
+                                    assert!(matches!(ct.kind(), ty::ConstKind::Param(_)))
                                 }
                                 ty::subst::GenericArgKind::Lifetime(..) => (),
                             },
@@ -69,7 +69,7 @@
         }
 
         fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
-            match c.val() {
+            match c.kind() {
                 ty::ConstKind::Param(..) => ControlFlow::Break(FoundParam),
                 _ => c.super_visit_with(self),
             }
diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs
index 2dab9ff..b0087fc 100644
--- a/compiler/rustc_const_eval/src/interpret/validity.rs
+++ b/compiler/rustc_const_eval/src/interpret/validity.rs
@@ -338,6 +338,10 @@
                         { "invalid drop function pointer in vtable (not pointing to a function)" },
                     err_ub!(InvalidVtableDropFn(..)) =>
                         { "invalid drop function pointer in vtable (function has incompatible signature)" },
+                    // Stacked Borrows errors can happen here, see https://github.com/rust-lang/miri/issues/2123.
+                    // (We assume there are no other MachineStop errors possible here.)
+                    InterpError::MachineStop(_) =>
+                        { "vtable pointer does not have permission to read drop function pointer" },
                 );
                 try_validation!(
                     self.ecx.read_size_and_align_from_vtable(vtable),
@@ -347,6 +351,10 @@
                     err_ub!(InvalidVtableAlignment(msg)) =>
                         { "invalid vtable: alignment {}", msg },
                     err_unsup!(ReadPointerAsBytes) => { "invalid size or align in vtable" },
+                    // Stacked Borrows errors can happen here, see https://github.com/rust-lang/miri/issues/2123.
+                    // (We assume there are no other MachineStop errors possible here.)
+                    InterpError::MachineStop(_) =>
+                        { "vtable pointer does not have permission to read size and alignment" },
                 );
                 // FIXME: More checks for the vtable.
             }
@@ -412,22 +420,27 @@
             self.path,
             err_ub!(AlignmentCheckFailed { required, has }) =>
                 {
-                    "an unaligned {} (required {} byte alignment but found {})",
-                    kind,
+                    "an unaligned {kind} (required {} byte alignment but found {})",
                     required.bytes(),
                     has.bytes()
                 },
             err_ub!(DanglingIntPointer(0, _)) =>
-                { "a null {}", kind },
+                { "a null {kind}" },
             err_ub!(DanglingIntPointer(i, _)) =>
-                { "a dangling {} (address 0x{:x} is unallocated)", kind, i },
+                { "a dangling {kind} (address 0x{i:x} is unallocated)" },
             err_ub!(PointerOutOfBounds { .. }) =>
-                { "a dangling {} (going beyond the bounds of its allocation)", kind },
+                { "a dangling {kind} (going beyond the bounds of its allocation)" },
             // This cannot happen during const-eval (because interning already detects
             // dangling pointers), but it can happen in Miri.
             err_ub!(PointerUseAfterFree(..)) =>
-                { "a dangling {} (use-after-free)", kind },
+                { "a dangling {kind} (use-after-free)" },
         );
+        // Do not allow pointers to uninhabited types.
+        if place.layout.abi.is_uninhabited() {
+            throw_validation_failure!(self.path,
+                { "a {kind} pointing to uninhabited type {}", place.layout.ty }
+            )
+        }
         // Recursive checking
         if let Some(ref mut ref_tracking) = self.ref_tracking {
             // Proceed recursively even for ZST, no reason to skip them!
@@ -531,15 +544,23 @@
                 let value = self.read_scalar(value)?;
                 // NOTE: Keep this in sync with the array optimization for int/float
                 // types below!
-                if M::enforce_number_validity(self.ecx) {
-                    // Integers/floats with number validity: Must be scalar bits, pointers are dangerous.
+                if M::enforce_number_init(self.ecx) {
+                    try_validation!(
+                        value.check_init(),
+                        self.path,
+                        err_ub!(InvalidUninitBytes(..)) =>
+                            { "{:x}", value } expected { "initialized bytes" }
+                    );
+                }
+                // Always check for number provenance during CTFE validation, even if the machine
+                // internally temporarily accepts number provenance.
+                if self.ctfe_mode.is_some() || M::enforce_number_no_provenance(self.ecx) {
                     // As a special exception we *do* match on a `Scalar` here, since we truly want
                     // to know its underlying representation (and *not* cast it to an integer).
-                    let is_bits =
-                        value.check_init().map_or(false, |v| matches!(v, Scalar::Int(..)));
-                    if !is_bits {
+                    let is_ptr = value.check_init().map_or(false, |v| matches!(v, Scalar::Ptr(..)));
+                    if is_ptr {
                         throw_validation_failure!(self.path,
-                            { "{:x}", value } expected { "initialized plain (non-pointer) bytes" }
+                            { "{:x}", value } expected { "plain (non-pointer) bytes" }
                         )
                     }
                 }
@@ -646,7 +667,7 @@
         let size = scalar_layout.size(self.ecx);
         let is_full_range = match scalar_layout {
             ScalarAbi::Initialized { .. } => {
-                if M::enforce_number_validity(self.ecx) {
+                if M::enforce_number_init(self.ecx) {
                     false // not "full" since uninit is not accepted
                 } else {
                     scalar_layout.is_always_valid(self.ecx)
@@ -905,10 +926,12 @@
                     return Ok(());
                 };
 
-                let allow_uninit_and_ptr = !M::enforce_number_validity(self.ecx);
+                // Always check for number provenance during CTFE validation, even if the machine
+                // internally temporarily accepts number provenance.
                 match alloc.check_bytes(
                     alloc_range(Size::ZERO, size),
-                    allow_uninit_and_ptr,
+                    /*allow_uninit*/ !M::enforce_number_init(self.ecx),
+                    /*allow_ptr*/ !(self.ctfe_mode.is_some() || M::enforce_number_no_provenance(self.ecx)),
                 ) {
                     // In the happy case, we needn't check anything else.
                     Ok(()) => {}
diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs
index 1ab461a..64a74e9 100644
--- a/compiler/rustc_const_eval/src/lib.rs
+++ b/compiler/rustc_const_eval/src/lib.rs
@@ -7,9 +7,9 @@
 #![feature(assert_matches)]
 #![feature(box_patterns)]
 #![feature(control_flow_enum)]
-#![feature(crate_visibility_modifier)]
 #![feature(decl_macro)]
 #![feature(exact_size_is_empty)]
+#![feature(let_chains)]
 #![feature(let_else)]
 #![feature(map_try_insert)]
 #![feature(min_specialization)]
@@ -20,6 +20,7 @@
 #![feature(trusted_len)]
 #![feature(trusted_step)]
 #![feature(try_blocks)]
+#![feature(yeet_expr)]
 #![recursion_limit = "256"]
 #![allow(rustc::potential_query_instability)]
 
@@ -33,27 +34,28 @@
 pub mod transform;
 pub mod util;
 
+use rustc_middle::ty;
 use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::ParamEnv;
 
 pub fn provide(providers: &mut Providers) {
     const_eval::provide(providers);
     providers.eval_to_const_value_raw = const_eval::eval_to_const_value_raw_provider;
     providers.eval_to_allocation_raw = const_eval::eval_to_allocation_raw_provider;
     providers.const_caller_location = const_eval::const_caller_location;
-    providers.try_destructure_const = |tcx, param_env_and_value| {
-        let (param_env, value) = param_env_and_value.into_parts();
-        const_eval::try_destructure_const(tcx, param_env, value).ok()
-    };
-    providers.const_to_valtree = |tcx, param_env_and_value| {
+    providers.try_destructure_const = |tcx, val| const_eval::try_destructure_const(tcx, val);
+    providers.eval_to_valtree = |tcx, param_env_and_value| {
         let (param_env, raw) = param_env_and_value.into_parts();
-        const_eval::const_to_valtree(tcx, param_env, raw)
+        const_eval::eval_to_valtree(tcx, param_env, raw)
+    };
+    providers.try_destructure_mir_constant = |tcx, param_env_and_value| {
+        let (param_env, value) = param_env_and_value.into_parts();
+        const_eval::try_destructure_mir_constant(tcx, param_env, value).ok()
     };
     providers.valtree_to_const_val = |tcx, (ty, valtree)| {
-        const_eval::valtree_to_const_value(tcx, ParamEnv::empty().and(ty), valtree)
+        const_eval::valtree_to_const_value(tcx, ty::ParamEnv::empty().and(ty), valtree)
     };
-    providers.deref_const = |tcx, param_env_and_value| {
+    providers.deref_mir_constant = |tcx, param_env_and_value| {
         let (param_env, value) = param_env_and_value.into_parts();
-        const_eval::deref_const(tcx, param_env, value)
+        const_eval::deref_mir_constant(tcx, param_env, value)
     };
 }
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
index 8d3bbef..069fbed 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
@@ -8,7 +8,6 @@
 use rustc_infer::traits::{ImplSource, Obligation, ObligationCause};
 use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor};
 use rustc_middle::mir::*;
-use rustc_middle::ty::cast::CastTy;
 use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts};
 use rustc_middle::ty::{self, adjustment::PointerCast, Instance, InstanceDef, Ty, TyCtxt};
 use rustc_middle::ty::{Binder, TraitPredicate, TraitRef, TypeFoldable};
@@ -229,18 +228,6 @@
 
         // The local type and predicate checks are not free and only relevant for `const fn`s.
         if self.const_kind() == hir::ConstContext::ConstFn {
-            // Prevent const trait methods from being annotated as `stable`.
-            // FIXME: Do this as part of stability checking.
-            if self.is_const_stable_const_fn() {
-                if crate::const_eval::is_parent_const_impl_raw(tcx, def_id) {
-                    self.ccx
-                        .tcx
-                        .sess
-                        .struct_span_err(self.span, "trait methods cannot be stable const fn")
-                        .emit();
-                }
-            }
-
             for (idx, local) in body.local_decls.iter_enumerated() {
                 // Handle the return place below.
                 if idx == RETURN_PLACE || local.internal {
@@ -533,37 +520,31 @@
             }
 
             Rvalue::Cast(
-                CastKind::Pointer(PointerCast::MutToConstPointer | PointerCast::ArrayToPointer),
-                _,
-                _,
-            ) => {}
-
-            Rvalue::Cast(
                 CastKind::Pointer(
-                    PointerCast::UnsafeFnPointer
+                    PointerCast::MutToConstPointer
+                    | PointerCast::ArrayToPointer
+                    | PointerCast::UnsafeFnPointer
                     | PointerCast::ClosureFnPointer(_)
                     | PointerCast::ReifyFnPointer,
                 ),
                 _,
                 _,
             ) => {
-                // Nothing to do here. Function pointer casts are allowed now.
+                // These are all okay; they only change the type, not the data.
             }
 
             Rvalue::Cast(CastKind::Pointer(PointerCast::Unsize), _, _) => {
-                // Nothing to check here (`check_local_or_return_ty` ensures no trait objects occur
-                // in the type of any local, which also excludes casts).
+                // Unsizing is implemented for CTFE.
             }
 
-            Rvalue::Cast(CastKind::Misc, ref operand, cast_ty) => {
-                let operand_ty = operand.ty(self.body, self.tcx);
-                let cast_in = CastTy::from_ty(operand_ty).expect("bad input type for cast");
-                let cast_out = CastTy::from_ty(cast_ty).expect("bad output type for cast");
-
-                if let (CastTy::Ptr(_) | CastTy::FnPtr, CastTy::Int(_)) = (cast_in, cast_out) {
-                    self.check_op(ops::RawPtrToIntCast);
-                }
+            Rvalue::Cast(CastKind::PointerExposeAddress, _, _) => {
+                self.check_op(ops::RawPtrToIntCast);
             }
+            Rvalue::Cast(CastKind::PointerFromExposedAddress, _, _) => {
+                // Since no pointer can ever get exposed (rejected above), this is easy to support.
+            }
+
+            Rvalue::Cast(CastKind::Misc, _, _) => {}
 
             Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _) => {}
             Rvalue::ShallowInitBox(_, _) => {}
@@ -702,8 +683,6 @@
 
     #[instrument(level = "debug", skip(self))]
     fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) {
-        use rustc_target::spec::abi::Abi::RustIntrinsic;
-
         self.super_terminator(terminator, location);
 
         match &terminator.kind {
@@ -725,8 +704,6 @@
                     }
                 };
 
-                let mut nonconst_call_permission = false;
-
                 // Attempting to call a trait method?
                 if let Some(trait_id) = tcx.trait_of_item(callee) {
                     trace!("attempting to call a trait method");
@@ -776,7 +753,7 @@
                                 callee = did;
                             }
 
-                            if let hir::Constness::NotConst = tcx.impl_constness(data.impl_def_id) {
+                            if let hir::Constness::NotConst = tcx.constness(data.impl_def_id) {
                                 self.check_op(ops::FnCallNonConst {
                                     caller,
                                     callee,
@@ -788,13 +765,12 @@
                             }
                         }
                         _ if !tcx.is_const_fn_raw(callee) => {
-                            // At this point, it is only legal when the caller is marked with
-                            // #[default_method_body_is_const], and the callee is in the same
-                            // trait.
-                            let callee_trait = tcx.trait_of_item(callee);
-                            if callee_trait.is_some()
-                                && tcx.has_attr(caller.to_def_id(), sym::default_method_body_is_const)
-                                && callee_trait == tcx.trait_of_item(caller)
+                            // At this point, it is only legal when the caller is in a trait
+                            // marked with #[const_trait], and the callee is in the same trait.
+                            let mut nonconst_call_permission = false;
+                            if let Some(callee_trait) = tcx.trait_of_item(callee)
+                                && tcx.has_attr(callee_trait, sym::const_trait)
+                                && Some(callee_trait) == tcx.trait_of_item(caller)
                                 // Can only call methods when it's `<Self as TheTrait>::f`.
                                 && tcx.types.self_param == substs.type_at(0)
                             {
@@ -885,19 +861,13 @@
                     return;
                 }
 
-                let is_intrinsic = tcx.fn_sig(callee).abi() == RustIntrinsic;
+                let is_intrinsic = tcx.is_intrinsic(callee);
 
                 if !tcx.is_const_fn_raw(callee) {
-                    if tcx.trait_of_item(callee).is_some() {
-                        if tcx.has_attr(callee, sym::default_method_body_is_const) {
-                            // To get to here we must have already found a const impl for the
-                            // trait, but for it to still be non-const can be that the impl is
-                            // using default method bodies.
-                            nonconst_call_permission = true;
-                        }
-                    }
-
-                    if !nonconst_call_permission {
+                    if !tcx.is_const_default_method(callee) {
+                        // To get to here we must have already found a const impl for the
+                        // trait, but for it to still be non-const can be that the impl is
+                        // using default method bodies.
                         self.check_op(ops::FnCallNonConst {
                             caller,
                             callee,
@@ -946,7 +916,7 @@
                 // have no `rustc_const_stable` attributes to be const-unstable as well. This
                 // should be fixed later.
                 let callee_is_unstable_unmarked = tcx.lookup_const_stability(callee).is_none()
-                    && tcx.lookup_stability(callee).map_or(false, |s| s.level.is_unstable());
+                    && tcx.lookup_stability(callee).map_or(false, |s| s.is_unstable());
                 if callee_is_unstable_unmarked {
                     trace!("callee_is_unstable_unmarked");
                     // We do not use `const` modifiers for intrinsic "functions", as intrinsics are
@@ -1065,7 +1035,7 @@
         .span_suggestion(
             attr_span,
             "if it is not part of the public API, make this function unstably const",
-            concat!(r#"#[rustc_const_unstable(feature = "...", issue = "...")]"#, '\n').to_owned(),
+            concat!(r#"#[rustc_const_unstable(feature = "...", issue = "...")]"#, '\n'),
             Applicability::HasPlaceholders,
         )
         .span_suggestion(
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/mod.rs b/compiler/rustc_const_eval/src/transform/check_consts/mod.rs
index 23e2afa..25b420b 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/mod.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/mod.rs
@@ -9,7 +9,7 @@
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_middle::mir;
 use rustc_middle::ty::{self, TyCtxt};
-use rustc_span::{sym, Symbol};
+use rustc_span::Symbol;
 
 pub use self::qualifs::Qualif;
 
@@ -84,34 +84,49 @@
 // functions are subject to more stringent restrictions than "const-unstable" functions: They
 // cannot use unstable features and can only call other "const-stable" functions.
 pub fn is_const_stable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
-    use attr::{ConstStability, Stability, StabilityLevel};
-
-    // A default body marked const is not const-stable because const
+    // A default body in a `#[const_trait]` is not const-stable because const
     // trait fns currently cannot be const-stable. We shouldn't
     // restrict default bodies to only call const-stable functions.
-    if tcx.has_attr(def_id, sym::default_method_body_is_const) {
+    if tcx.is_const_default_method(def_id) {
         return false;
     }
 
     // Const-stability is only relevant for `const fn`.
     assert!(tcx.is_const_fn_raw(def_id));
 
-    // Functions with `#[rustc_const_unstable]` are const-unstable.
+    // A function is only const-stable if it has `#[rustc_const_stable]` or it the trait it belongs
+    // to is const-stable.
     match tcx.lookup_const_stability(def_id) {
-        Some(ConstStability { level: StabilityLevel::Unstable { .. }, .. }) => return false,
-        Some(ConstStability { level: StabilityLevel::Stable { .. }, .. }) => return true,
-        None => {}
+        Some(stab) => stab.is_const_stable(),
+        None if is_parent_const_stable_trait(tcx, def_id) => {
+            // Remove this when `#![feature(const_trait_impl)]` is stabilized,
+            // returning `true` unconditionally.
+            tcx.sess.delay_span_bug(
+                tcx.def_span(def_id),
+                "trait implementations cannot be const stable yet",
+            );
+            true
+        }
+        None => false, // By default, items are not const stable.
     }
+}
 
-    // Functions with `#[unstable]` are const-unstable.
-    //
-    // FIXME(ecstaticmorse): We should keep const-stability attributes wholly separate from normal stability
-    // attributes. `#[unstable]` should be irrelevant.
-    if let Some(Stability { level: StabilityLevel::Unstable { .. }, .. }) =
-        tcx.lookup_stability(def_id)
-    {
+fn is_parent_const_stable_trait(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
+    let local_def_id = def_id.expect_local();
+    let hir_id = tcx.local_def_id_to_hir_id(local_def_id);
+
+    let Some(parent) = tcx.hir().find_parent_node(hir_id) else { return false };
+    let parent_def = tcx.hir().get(parent);
+
+    if !matches!(
+        parent_def,
+        hir::Node::Item(hir::Item {
+            kind: hir::ItemKind::Impl(hir::Impl { constness: hir::Constness::Const, .. }),
+            ..
+        })
+    ) {
         return false;
     }
 
-    true
+    tcx.lookup_const_stability(parent.owner).map_or(false, |stab| stab.is_const_stable())
 }
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs
index 122471b..0c58722 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs
@@ -10,7 +10,8 @@
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
 use rustc_middle::ty::{
-    suggest_constraining_type_param, Adt, Closure, FnDef, FnPtr, Param, TraitPredicate, Ty,
+    suggest_constraining_type_param, Adt, Closure, DefIdTree, FnDef, FnPtr, Param, TraitPredicate,
+    Ty,
 };
 use rustc_middle::ty::{Binder, BoundConstness, ImplPolarity, TraitRef};
 use rustc_session::parse::feature_err;
@@ -89,7 +90,10 @@
         ccx: &ConstCx<'_, 'tcx>,
         span: Span,
     ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
-        ccx.tcx.sess.struct_span_err(span, "function pointers are not allowed in const fn")
+        ccx.tcx.sess.struct_span_err(
+            span,
+            &format!("function pointer calls are not allowed in {}s", ccx.const_kind()),
+        )
     }
 }
 
@@ -297,6 +301,15 @@
                 diag_trait(&mut err, self_ty, tcx.lang_items().deref_trait().unwrap());
                 err
             }
+            _ if tcx.opt_parent(callee) == tcx.get_diagnostic_item(sym::ArgumentV1Methods) => {
+                struct_span_err!(
+                    ccx.tcx.sess,
+                    span,
+                    E0015,
+                    "cannot call non-const formatting macro in {}s",
+                    ccx.const_kind(),
+                )
+            }
             _ => struct_span_err!(
                 ccx.tcx.sess,
                 span,
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
index 9fd94dc..6e5a0c8 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
@@ -353,7 +353,8 @@
 
     // Check the qualifs of the value of `const` items.
     if let Some(ct) = constant.literal.const_for_ty() {
-        if let ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs: _, promoted }) = ct.val() {
+        if let ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs: _, promoted }) = ct.kind()
+        {
             // Use qualifs of the type for the promoted. Promoteds in MIR body should be possible
             // only for `NeedsNonConstDrop` with precise drop checking. This is the only const
             // check performed after the promotion. Verify that with an assertion.
diff --git a/compiler/rustc_const_eval/src/transform/promote_consts.rs b/compiler/rustc_const_eval/src/transform/promote_consts.rs
index f88538f..3595a48 100644
--- a/compiler/rustc_const_eval/src/transform/promote_consts.rs
+++ b/compiler/rustc_const_eval/src/transform/promote_consts.rs
@@ -16,7 +16,6 @@
 use rustc_middle::mir::traversal::ReversePostorderIter;
 use rustc_middle::mir::visit::{MutVisitor, MutatingUseContext, PlaceContext, Visitor};
 use rustc_middle::mir::*;
-use rustc_middle::ty::cast::CastTy;
 use rustc_middle::ty::subst::InternalSubsts;
 use rustc_middle::ty::{self, List, TyCtxt, TypeFoldable};
 use rustc_span::Span;
@@ -502,18 +501,12 @@
 
             Rvalue::ThreadLocalRef(_) => return Err(Unpromotable),
 
-            Rvalue::Cast(kind, operand, cast_ty) => {
-                if matches!(kind, CastKind::Misc) {
-                    let operand_ty = operand.ty(self.body, self.tcx);
-                    let cast_in = CastTy::from_ty(operand_ty).expect("bad input type for cast");
-                    let cast_out = CastTy::from_ty(*cast_ty).expect("bad output type for cast");
-                    if let (CastTy::Ptr(_) | CastTy::FnPtr, CastTy::Int(_)) = (cast_in, cast_out) {
-                        // ptr-to-int casts are not possible in consts and thus not promotable
-                        return Err(Unpromotable);
-                    }
-                    // int-to-ptr casts are fine, they just use the integer value at pointer type.
-                }
+            // ptr-to-int casts are not possible in consts and thus not promotable
+            Rvalue::Cast(CastKind::PointerExposeAddress, _, _) => return Err(Unpromotable),
 
+            // all other casts including int-to-ptr casts are fine, they just use the integer value
+            // at pointer type.
+            Rvalue::Cast(_, operand, _) => {
                 self.validate_operand(operand)?;
             }
 
@@ -772,7 +765,7 @@
                         let unit = Rvalue::Use(Operand::Constant(Box::new(Constant {
                             span: statement.source_info.span,
                             user_ty: None,
-                            literal: ty::Const::zero_sized(self.tcx, self.tcx.types.unit).into(),
+                            literal: ConstantKind::zero_sized(self.tcx.types.unit),
                         })));
                         mem::replace(rhs, unit)
                     },
@@ -788,7 +781,7 @@
             } else {
                 let terminator = self.source[loc.block].terminator_mut();
                 let target = match terminator.kind {
-                    TerminatorKind::Call { destination: Some((_, target)), .. } => target,
+                    TerminatorKind::Call { target: Some(target), .. } => target,
                     ref kind => {
                         span_bug!(terminator.source_info.span, "{:?} not promotable", kind);
                     }
@@ -814,7 +807,8 @@
                             func,
                             args,
                             cleanup: None,
-                            destination: Some((Place::from(new_temp), new_target)),
+                            destination: Place::from(new_temp),
+                            target: Some(new_target),
                             from_hir_call,
                             fn_span,
                         },
@@ -841,26 +835,25 @@
             let mut promoted_operand = |ty, span| {
                 promoted.span = span;
                 promoted.local_decls[RETURN_PLACE] = LocalDecl::new(ty, span);
+                let _const = tcx.mk_const(ty::ConstS {
+                    ty,
+                    kind: ty::ConstKind::Unevaluated(ty::Unevaluated {
+                        def,
+                        substs: InternalSubsts::for_item(tcx, def.did, |param, _| {
+                            if let ty::GenericParamDefKind::Lifetime = param.kind {
+                                tcx.lifetimes.re_erased.into()
+                            } else {
+                                tcx.mk_param_from_def(param)
+                            }
+                        }),
+                        promoted: Some(promoted_id),
+                    }),
+                });
 
                 Operand::Constant(Box::new(Constant {
                     span,
                     user_ty: None,
-                    literal: tcx
-                        .mk_const(ty::ConstS {
-                            ty,
-                            val: ty::ConstKind::Unevaluated(ty::Unevaluated {
-                                def,
-                                substs: InternalSubsts::for_item(tcx, def.did, |param, _| {
-                                    if let ty::GenericParamDefKind::Lifetime = param.kind {
-                                        tcx.lifetimes.re_erased.into()
-                                    } else {
-                                        tcx.mk_param_from_def(param)
-                                    }
-                                }),
-                                promoted: Some(promoted_id),
-                            }),
-                        })
-                        .into(),
+                    literal: ConstantKind::from_const(_const, tcx),
                 }))
             };
             let (blocks, local_decls) = self.source.basic_blocks_and_local_decls_mut();
@@ -1054,11 +1047,9 @@
         {
             if let Operand::Constant(box Constant { literal, .. }) = func {
                 if let ty::FnDef(def_id, _) = *literal.ty().kind() {
-                    if let Some((destination_place, _)) = destination {
-                        if destination_place == place {
-                            if ccx.tcx.is_const_fn(def_id) {
-                                return true;
-                            }
+                    if destination == place {
+                        if ccx.tcx.is_const_fn(def_id) {
+                            return true;
                         }
                     }
                 }
diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs
index 3ce33d5..66d66ea 100644
--- a/compiler/rustc_const_eval/src/transform/validate.rs
+++ b/compiler/rustc_const_eval/src/transform/validate.rs
@@ -4,6 +4,7 @@
 use rustc_index::bit_set::BitSet;
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_middle::mir::interpret::Scalar;
+use rustc_middle::mir::visit::NonUseContext::VarDebugInfo;
 use rustc_middle::mir::visit::{PlaceContext, Visitor};
 use rustc_middle::mir::{
     traversal, AggregateKind, BasicBlock, BinOp, Body, BorrowKind, Local, Location, MirPass,
@@ -13,7 +14,7 @@
 use rustc_middle::ty::fold::BottomUpFolder;
 use rustc_middle::ty::{self, InstanceDef, ParamEnv, Ty, TyCtxt, TypeFoldable};
 use rustc_mir_dataflow::impls::MaybeStorageLive;
-use rustc_mir_dataflow::storage::AlwaysLiveLocals;
+use rustc_mir_dataflow::storage::always_live_locals;
 use rustc_mir_dataflow::{Analysis, ResultsCursor};
 use rustc_target::abi::{Size, VariantIdx};
 
@@ -47,7 +48,7 @@
         let param_env = tcx.param_env(def_id);
         let mir_phase = self.mir_phase;
 
-        let always_live_locals = AlwaysLiveLocals::new(body);
+        let always_live_locals = always_live_locals(body);
         let storage_liveness = MaybeStorageLive::new(always_live_locals)
             .into_engine(tcx, body)
             .iterate_to_fixpoint()
@@ -239,72 +240,94 @@
         context: PlaceContext,
         location: Location,
     ) {
-        if let ProjectionElem::Index(index) = elem {
-            let index_ty = self.body.local_decls[index].ty;
-            if index_ty != self.tcx.types.usize {
-                self.fail(location, format!("bad index ({:?} != usize)", index_ty))
+        match elem {
+            ProjectionElem::Index(index) => {
+                let index_ty = self.body.local_decls[index].ty;
+                if index_ty != self.tcx.types.usize {
+                    self.fail(location, format!("bad index ({:?} != usize)", index_ty))
+                }
             }
-        }
-        if let ProjectionElem::Field(f, ty) = elem {
-            let parent = Place { local, projection: self.tcx.intern_place_elems(proj_base) };
-            let parent_ty = parent.ty(&self.body.local_decls, self.tcx);
-            let fail_out_of_bounds = |this: &Self, location| {
-                this.fail(location, format!("Out of bounds field {:?} for {:?}", f, parent_ty));
-            };
-            let check_equal = |this: &Self, location, f_ty| {
-                if !this.mir_assign_valid_types(ty, f_ty) {
-                    this.fail(
+            ProjectionElem::Deref if self.mir_phase >= MirPhase::GeneratorsLowered => {
+                let base_ty = Place::ty_from(local, proj_base, &self.body.local_decls, self.tcx).ty;
+
+                if base_ty.is_box() {
+                    self.fail(
+                        location,
+                        format!("{:?} dereferenced after ElaborateBoxDerefs", base_ty),
+                    )
+                }
+            }
+            ProjectionElem::Field(f, ty) => {
+                let parent = Place { local, projection: self.tcx.intern_place_elems(proj_base) };
+                let parent_ty = parent.ty(&self.body.local_decls, self.tcx);
+                let fail_out_of_bounds = |this: &Self, location| {
+                    this.fail(location, format!("Out of bounds field {:?} for {:?}", f, parent_ty));
+                };
+                let check_equal = |this: &Self, location, f_ty| {
+                    if !this.mir_assign_valid_types(ty, f_ty) {
+                        this.fail(
                         location,
                         format!(
                             "Field projection `{:?}.{:?}` specified type `{:?}`, but actual type is {:?}",
                             parent, f, ty, f_ty
                         )
                     )
-                }
-            };
-            match parent_ty.ty.kind() {
-                ty::Tuple(fields) => {
-                    let Some(f_ty) = fields.get(f.as_usize()) else {
-                        fail_out_of_bounds(self, location);
-                        return;
-                    };
-                    check_equal(self, location, *f_ty);
-                }
-                ty::Adt(adt_def, substs) => {
-                    let var = parent_ty.variant_index.unwrap_or(VariantIdx::from_u32(0));
-                    let Some(field) = adt_def.variant(var).fields.get(f.as_usize()) else {
-                        fail_out_of_bounds(self, location);
-                        return;
-                    };
-                    check_equal(self, location, field.ty(self.tcx, substs));
-                }
-                ty::Closure(_, substs) => {
-                    let substs = substs.as_closure();
-                    let Some(f_ty) = substs.upvar_tys().nth(f.as_usize()) else {
-                        fail_out_of_bounds(self, location);
-                        return;
-                    };
-                    check_equal(self, location, f_ty);
-                }
-                ty::Generator(_, substs, _) => {
-                    let substs = substs.as_generator();
-                    let Some(f_ty) = substs.upvar_tys().nth(f.as_usize()) else {
-                        fail_out_of_bounds(self, location);
-                        return;
-                    };
-                    check_equal(self, location, f_ty);
-                }
-                _ => {
-                    self.fail(location, format!("{:?} does not have fields", parent_ty.ty));
+                    }
+                };
+
+                match parent_ty.ty.kind() {
+                    ty::Tuple(fields) => {
+                        let Some(f_ty) = fields.get(f.as_usize()) else {
+                            fail_out_of_bounds(self, location);
+                            return;
+                        };
+                        check_equal(self, location, *f_ty);
+                    }
+                    ty::Adt(adt_def, substs) => {
+                        let var = parent_ty.variant_index.unwrap_or(VariantIdx::from_u32(0));
+                        let Some(field) = adt_def.variant(var).fields.get(f.as_usize()) else {
+                            fail_out_of_bounds(self, location);
+                            return;
+                        };
+                        check_equal(self, location, field.ty(self.tcx, substs));
+                    }
+                    ty::Closure(_, substs) => {
+                        let substs = substs.as_closure();
+                        let Some(f_ty) = substs.upvar_tys().nth(f.as_usize()) else {
+                            fail_out_of_bounds(self, location);
+                            return;
+                        };
+                        check_equal(self, location, f_ty);
+                    }
+                    ty::Generator(_, substs, _) => {
+                        let substs = substs.as_generator();
+                        let Some(f_ty) = substs.upvar_tys().nth(f.as_usize()) else {
+                            fail_out_of_bounds(self, location);
+                            return;
+                        };
+                        check_equal(self, location, f_ty);
+                    }
+                    _ => {
+                        self.fail(location, format!("{:?} does not have fields", parent_ty.ty));
+                    }
                 }
             }
+            _ => {}
         }
         self.super_projection_elem(local, proj_base, elem, context, location);
     }
 
-    fn visit_place(&mut self, place: &Place<'tcx>, _: PlaceContext, _: Location) {
+    fn visit_place(&mut self, place: &Place<'tcx>, cntxt: PlaceContext, location: Location) {
         // Set off any `bug!`s in the type computation code
         let _ = place.ty(&self.body.local_decls, self.tcx);
+
+        if self.mir_phase >= MirPhase::Derefered
+            && place.projection.len() > 1
+            && cntxt != PlaceContext::NonUse(VarDebugInfo)
+            && place.projection[1..].contains(&ProjectionElem::Deref)
+        {
+            self.fail(location, format!("{:?}, has deref at the wrong place", place));
+        }
     }
 
     fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
@@ -673,7 +696,7 @@
                     self.check_edge(location, *unwind, EdgeKind::Unwind);
                 }
             }
-            TerminatorKind::Call { func, args, destination, cleanup, .. } => {
+            TerminatorKind::Call { func, args, destination, target, cleanup, .. } => {
                 let func_ty = func.ty(&self.body.local_decls, self.tcx);
                 match func_ty.kind() {
                     ty::FnPtr(..) | ty::FnDef(..) => {}
@@ -682,7 +705,7 @@
                         format!("encountered non-callable type {} in `Call` terminator", func_ty),
                     ),
                 }
-                if let Some((_, target)) = destination {
+                if let Some(target) = target {
                     self.check_edge(location, *target, EdgeKind::Normal);
                 }
                 if let Some(cleanup) = cleanup {
@@ -693,9 +716,7 @@
                 // passed by a reference to the callee. Consequently they must be non-overlapping.
                 // Currently this simply checks for duplicate places.
                 self.place_cache.clear();
-                if let Some((destination, _)) = destination {
-                    self.place_cache.push(destination.as_ref());
-                }
+                self.place_cache.push(destination.as_ref());
                 for arg in args {
                     if let Operand::Move(place) = arg {
                         self.place_cache.push(place.as_ref());
diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml
index 7cc8b5c..3192fc4 100644
--- a/compiler/rustc_data_structures/Cargo.toml
+++ b/compiler/rustc_data_structures/Cargo.toml
@@ -9,7 +9,7 @@
 [dependencies]
 arrayvec = { version = "0.7", default-features = false }
 ena = "0.14"
-indexmap = { version = "1.8.0" }
+indexmap = { version = "1.9.1" }
 tracing = "0.1"
 jobserver_crate = { version = "0.1.13", package = "jobserver" }
 rustc_serialize = { path = "../rustc_serialize" }
@@ -17,8 +17,8 @@
 rustc_graphviz = { path = "../rustc_graphviz" }
 cfg-if = "0.1.2"
 stable_deref_trait = "1.0.0"
-rayon = { version = "0.3.2", package = "rustc-rayon", optional = true }
-rayon-core = { version = "0.3.2", package = "rustc-rayon-core", optional = true }
+rayon = { version = "0.4.0", package = "rustc-rayon", optional = true }
+rayon-core = { version = "0.4.0", package = "rustc-rayon-core", optional = true }
 rustc-hash = "1.1.0"
 smallvec = { version = "1.6.1", features = ["const_generics", "union", "may_dangle"] }
 rustc_index = { path = "../rustc_index", package = "rustc_index" }
diff --git a/compiler/rustc_data_structures/src/base_n/tests.rs b/compiler/rustc_data_structures/src/base_n/tests.rs
index b68ef1e..2be2f05 100644
--- a/compiler/rustc_data_structures/src/base_n/tests.rs
+++ b/compiler/rustc_data_structures/src/base_n/tests.rs
@@ -15,7 +15,9 @@
         test(u64::MAX as u128, base);
         test(u128::MAX, base);
 
-        for i in 0..1_000 {
+        const N: u128 = if cfg!(miri) { 10 } else { 1000 };
+
+        for i in 0..N {
             test(i * 983, base);
         }
     }
diff --git a/compiler/rustc_data_structures/src/fingerprint.rs b/compiler/rustc_data_structures/src/fingerprint.rs
index c88f3e7..5ff2d18 100644
--- a/compiler/rustc_data_structures/src/fingerprint.rs
+++ b/compiler/rustc_data_structures/src/fingerprint.rs
@@ -1,5 +1,5 @@
 use crate::stable_hasher;
-use rustc_serialize::{Decodable, Encodable};
+use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
 use std::convert::TryInto;
 use std::hash::{Hash, Hasher};
 
@@ -142,15 +142,14 @@
 
 impl_stable_hash_via_hash!(Fingerprint);
 
-impl<E: rustc_serialize::Encoder> Encodable<E> for Fingerprint {
+impl<E: Encoder> Encodable<E> for Fingerprint {
     #[inline]
-    fn encode(&self, s: &mut E) -> Result<(), E::Error> {
-        s.emit_raw_bytes(&self.to_le_bytes())?;
-        Ok(())
+    fn encode(&self, s: &mut E) {
+        s.emit_raw_bytes(&self.to_le_bytes());
     }
 }
 
-impl<D: rustc_serialize::Decoder> Decodable<D> for Fingerprint {
+impl<D: Decoder> Decodable<D> for Fingerprint {
     #[inline]
     fn decode(d: &mut D) -> Self {
         Fingerprint::from_le_bytes(d.read_raw_bytes(16).try_into().unwrap())
@@ -185,16 +184,16 @@
     }
 }
 
-impl<E: rustc_serialize::Encoder> Encodable<E> for PackedFingerprint {
+impl<E: Encoder> Encodable<E> for PackedFingerprint {
     #[inline]
-    fn encode(&self, s: &mut E) -> Result<(), E::Error> {
+    fn encode(&self, s: &mut E) {
         // Copy to avoid taking reference to packed field.
         let copy = self.0;
-        copy.encode(s)
+        copy.encode(s);
     }
 }
 
-impl<D: rustc_serialize::Decoder> Decodable<D> for PackedFingerprint {
+impl<D: Decoder> Decodable<D> for PackedFingerprint {
     #[inline]
     fn decode(d: &mut D) -> Self {
         Self(Fingerprint::decode(d))
diff --git a/compiler/rustc_data_structures/src/graph/scc/tests.rs b/compiler/rustc_data_structures/src/graph/scc/tests.rs
index 364005e..9940fee 100644
--- a/compiler/rustc_data_structures/src/graph/scc/tests.rs
+++ b/compiler/rustc_data_structures/src/graph/scc/tests.rs
@@ -156,7 +156,10 @@
     v

      */
+    #[cfg(not(miri))]
     const NR_NODES: usize = 1 << 14;
+    #[cfg(miri)]
+    const NR_NODES: usize = 1 << 3;
     let mut nodes = vec![];
     for i in 1..NR_NODES {
         nodes.push((i - 1, i));
diff --git a/compiler/rustc_data_structures/src/jobserver.rs b/compiler/rustc_data_structures/src/jobserver.rs
index 41605af..09baa30 100644
--- a/compiler/rustc_data_structures/src/jobserver.rs
+++ b/compiler/rustc_data_structures/src/jobserver.rs
@@ -1,5 +1,5 @@
 pub use jobserver_crate::Client;
-use std::lazy::SyncLazy;
+use std::sync::LazyLock;
 
 // We can only call `from_env` once per process
 
@@ -18,7 +18,7 @@
 // Also note that we stick this in a global because there could be
 // multiple rustc instances in this process, and the jobserver is
 // per-process.
-static GLOBAL_CLIENT: SyncLazy<Client> = SyncLazy::new(|| unsafe {
+static GLOBAL_CLIENT: LazyLock<Client> = LazyLock::new(|| unsafe {
     Client::from_env().unwrap_or_else(|| {
         let client = Client::new(32).expect("failed to create jobserver");
         // Acquire a token for the main thread which we can release later
diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs
index 76ae17f..390a44d 100644
--- a/compiler/rustc_data_structures/src/lib.rs
+++ b/compiler/rustc_data_structures/src/lib.rs
@@ -11,10 +11,7 @@
 #![feature(associated_type_bounds)]
 #![feature(auto_traits)]
 #![feature(control_flow_enum)]
-#![feature(core_intrinsics)]
 #![feature(extend_one)]
-#![feature(generator_trait)]
-#![feature(generators)]
 #![feature(let_else)]
 #![feature(hash_raw_entry)]
 #![feature(hasher_prefixfree_extras)]
@@ -46,26 +43,6 @@
     f()
 }
 
-#[macro_export]
-macro_rules! likely {
-    ($e:expr) => {
-        match $e {
-            #[allow(unused_unsafe)]
-            e => unsafe { std::intrinsics::likely(e) },
-        }
-    };
-}
-
-#[macro_export]
-macro_rules! unlikely {
-    ($e:expr) => {
-        match $e {
-            #[allow(unused_unsafe)]
-            e => unsafe { std::intrinsics::unlikely(e) },
-        }
-    };
-}
-
 pub mod base_n;
 pub mod binary_search_util;
 pub mod captures;
@@ -114,9 +91,6 @@
 pub use ena::undo_log;
 pub use ena::unify;
 
-use std::ops::{Generator, GeneratorState};
-use std::pin::Pin;
-
 pub struct OnDrop<F: Fn()>(pub F);
 
 impl<F: Fn()> OnDrop<F> {
@@ -135,26 +109,6 @@
     }
 }
 
-struct IterFromGenerator<G>(G);
-
-impl<G: Generator<Return = ()> + Unpin> Iterator for IterFromGenerator<G> {
-    type Item = G::Yield;
-
-    fn next(&mut self) -> Option<Self::Item> {
-        match Pin::new(&mut self.0).resume(()) {
-            GeneratorState::Yielded(n) => Some(n),
-            GeneratorState::Complete(_) => None,
-        }
-    }
-}
-
-/// An adapter for turning a generator closure into an iterator, similar to `iter::from_fn`.
-pub fn iter_from_generator<G: Generator<Return = ()> + Unpin>(
-    generator: G,
-) -> impl Iterator<Item = G::Yield> {
-    IterFromGenerator(generator)
-}
-
 // See comments in src/librustc_middle/lib.rs
 #[doc(hidden)]
 pub fn __noop_fix_for_27438() {}
diff --git a/compiler/rustc_data_structures/src/obligation_forest/mod.rs b/compiler/rustc_data_structures/src/obligation_forest/mod.rs
index 74f432a..07a96dd 100644
--- a/compiler/rustc_data_structures/src/obligation_forest/mod.rs
+++ b/compiler/rustc_data_structures/src/obligation_forest/mod.rs
@@ -42,7 +42,7 @@
 //!   now considered to be in error.
 //!
 //! When the call to `process_obligations` completes, you get back an `Outcome`,
-//! which includes three bits of information:
+//! which includes two bits of information:
 //!
 //! - `completed`: a list of obligations where processing was fully
 //!   completed without error (meaning that all transitive subobligations
@@ -53,13 +53,10 @@
 //!   all the obligations in `C` have been found completed.
 //! - `errors`: a list of errors that occurred and associated backtraces
 //!   at the time of error, which can be used to give context to the user.
-//! - `stalled`: if true, then none of the existing obligations were
-//!   *shallowly successful* (that is, no callback returned `Changed(_)`).
-//!   This implies that all obligations were either errors or returned an
-//!   ambiguous result, which means that any further calls to
-//!   `process_obligations` would simply yield back further ambiguous
-//!   results. This is used by the `FulfillmentContext` to decide when it
-//!   has reached a steady state.
+//!
+//! Upon completion, none of the existing obligations were *shallowly
+//! successful* (that is, no callback returned `Changed(_)`). This implies that
+//! all obligations were either errors or returned an ambiguous result.
 //!
 //! ### Implementation details
 //!
@@ -99,6 +96,8 @@
     type Obligation: ForestObligation;
     type Error: Debug;
 
+    fn needs_process_obligation(&self, obligation: &Self::Obligation) -> bool;
+
     fn process_obligation(
         &mut self,
         obligation: &mut Self::Obligation,
@@ -146,7 +145,7 @@
 
     /// A cache of the nodes in `nodes`, indexed by predicate. Unfortunately,
     /// its contents are not guaranteed to match those of `nodes`. See the
-    /// comments in [`Self::process_obligation` for details.
+    /// comments in `Self::process_obligation` for details.
     active_cache: FxHashMap<O::CacheKey, usize>,
 
     /// A vector reused in [Self::compress()] and [Self::find_cycles_from_node()],
@@ -260,8 +259,6 @@
     type Obligation;
 
     fn new() -> Self;
-    fn mark_not_stalled(&mut self);
-    fn is_stalled(&self) -> bool;
     fn record_completed(&mut self, outcome: &Self::Obligation);
     fn record_error(&mut self, error: Self::Error);
 }
@@ -270,14 +267,6 @@
 pub struct Outcome<O, E> {
     /// Backtrace of obligations that were found to be in error.
     pub errors: Vec<Error<O, E>>,
-
-    /// If true, then we saw no successful obligations, which means
-    /// there is no point in further iteration. This is based on the
-    /// assumption that when trait matching returns `Error` or
-    /// `Unchanged`, those results do not affect environmental
-    /// inference state. (Note that if we invoke `process_obligations`
-    /// with no pending obligations, stalled will be true.)
-    pub stalled: bool,
 }
 
 impl<O, E> OutcomeTrait for Outcome<O, E> {
@@ -285,15 +274,7 @@
     type Obligation = O;
 
     fn new() -> Self {
-        Self { stalled: true, errors: vec![] }
-    }
-
-    fn mark_not_stalled(&mut self) {
-        self.stalled = false;
-    }
-
-    fn is_stalled(&self) -> bool {
-        self.stalled
+        Self { errors: vec![] }
     }
 
     fn record_completed(&mut self, _outcome: &Self::Obligation) {
@@ -415,10 +396,7 @@
             .insert(node.obligation.as_cache_key());
     }
 
-    /// Performs a pass through the obligation list. This must
-    /// be called in a loop until `outcome.stalled` is false.
-    ///
-    /// This _cannot_ be unrolled (presently, at least).
+    /// Performs a fixpoint computation over the obligation list.
     #[inline(never)]
     pub fn process_obligations<P, OUT>(&mut self, processor: &mut P) -> OUT
     where
@@ -427,55 +405,69 @@
     {
         let mut outcome = OUT::new();
 
-        // Note that the loop body can append new nodes, and those new nodes
-        // will then be processed by subsequent iterations of the loop.
-        //
-        // We can't use an iterator for the loop because `self.nodes` is
-        // appended to and the borrow checker would complain. We also can't use
-        // `for index in 0..self.nodes.len() { ... }` because the range would
-        // be computed with the initial length, and we would miss the appended
-        // nodes. Therefore we use a `while` loop.
-        let mut index = 0;
-        while let Some(node) = self.nodes.get_mut(index) {
-            // `processor.process_obligation` can modify the predicate within
-            // `node.obligation`, and that predicate is the key used for
-            // `self.active_cache`. This means that `self.active_cache` can get
-            // out of sync with `nodes`. It's not very common, but it does
-            // happen, and code in `compress` has to allow for it.
-            if node.state.get() != NodeState::Pending {
-                index += 1;
-                continue;
-            }
+        // Fixpoint computation: we repeat until the inner loop stalls.
+        loop {
+            let mut has_changed = false;
 
-            match processor.process_obligation(&mut node.obligation) {
-                ProcessResult::Unchanged => {
-                    // No change in state.
+            // Note that the loop body can append new nodes, and those new nodes
+            // will then be processed by subsequent iterations of the loop.
+            //
+            // We can't use an iterator for the loop because `self.nodes` is
+            // appended to and the borrow checker would complain. We also can't use
+            // `for index in 0..self.nodes.len() { ... }` because the range would
+            // be computed with the initial length, and we would miss the appended
+            // nodes. Therefore we use a `while` loop.
+            let mut index = 0;
+            while let Some(node) = self.nodes.get_mut(index) {
+                if node.state.get() != NodeState::Pending
+                    || !processor.needs_process_obligation(&node.obligation)
+                {
+                    index += 1;
+                    continue;
                 }
-                ProcessResult::Changed(children) => {
-                    // We are not (yet) stalled.
-                    outcome.mark_not_stalled();
-                    node.state.set(NodeState::Success);
 
-                    for child in children {
-                        let st = self.register_obligation_at(child, Some(index));
-                        if let Err(()) = st {
-                            // Error already reported - propagate it
-                            // to our node.
-                            self.error_at(index);
+                // `processor.process_obligation` can modify the predicate within
+                // `node.obligation`, and that predicate is the key used for
+                // `self.active_cache`. This means that `self.active_cache` can get
+                // out of sync with `nodes`. It's not very common, but it does
+                // happen, and code in `compress` has to allow for it.
+
+                match processor.process_obligation(&mut node.obligation) {
+                    ProcessResult::Unchanged => {
+                        // No change in state.
+                    }
+                    ProcessResult::Changed(children) => {
+                        // We are not (yet) stalled.
+                        has_changed = true;
+                        node.state.set(NodeState::Success);
+
+                        for child in children {
+                            let st = self.register_obligation_at(child, Some(index));
+                            if let Err(()) = st {
+                                // Error already reported - propagate it
+                                // to our node.
+                                self.error_at(index);
+                            }
                         }
                     }
+                    ProcessResult::Error(err) => {
+                        has_changed = true;
+                        outcome.record_error(Error { error: err, backtrace: self.error_at(index) });
+                    }
                 }
-                ProcessResult::Error(err) => {
-                    outcome.mark_not_stalled();
-                    outcome.record_error(Error { error: err, backtrace: self.error_at(index) });
-                }
+                index += 1;
             }
-            index += 1;
-        }
 
-        // There's no need to perform marking, cycle processing and compression when nothing
-        // changed.
-        if !outcome.is_stalled() {
+            // If unchanged, then we saw no successful obligations, which means
+            // there is no point in further iteration. This is based on the
+            // assumption that when trait matching returns `Error` or
+            // `Unchanged`, those results do not affect environmental inference
+            // state. (Note that this will occur if we invoke
+            // `process_obligations` with no pending obligations.)
+            if !has_changed {
+                break;
+            }
+
             self.mark_successes();
             self.process_cycles(processor);
             self.compress(|obl| outcome.record_completed(obl));
@@ -634,17 +626,14 @@
                     }
                 }
                 NodeState::Done => {
-                    // This lookup can fail because the contents of
+                    // The removal lookup might fail because the contents of
                     // `self.active_cache` are not guaranteed to match those of
                     // `self.nodes`. See the comment in `process_obligation`
                     // for more details.
-                    if let Some((predicate, _)) =
-                        self.active_cache.remove_entry(&node.obligation.as_cache_key())
-                    {
-                        self.done_cache.insert(predicate);
-                    } else {
-                        self.done_cache.insert(node.obligation.as_cache_key().clone());
-                    }
+                    let cache_key = node.obligation.as_cache_key();
+                    self.active_cache.remove(&cache_key);
+                    self.done_cache.insert(cache_key);
+
                     // Extract the success stories.
                     outcome_cb(&node.obligation);
                     node_rewrites[index] = orig_nodes_len;
diff --git a/compiler/rustc_data_structures/src/obligation_forest/tests.rs b/compiler/rustc_data_structures/src/obligation_forest/tests.rs
index 371c62c..e2991aa 100644
--- a/compiler/rustc_data_structures/src/obligation_forest/tests.rs
+++ b/compiler/rustc_data_structures/src/obligation_forest/tests.rs
@@ -20,7 +20,6 @@
 struct TestOutcome<O, E> {
     pub completed: Vec<O>,
     pub errors: Vec<Error<O, E>>,
-    pub stalled: bool,
 }
 
 impl<O, E> OutcomeTrait for TestOutcome<O, E>
@@ -31,15 +30,7 @@
     type Obligation = O;
 
     fn new() -> Self {
-        Self { errors: vec![], stalled: false, completed: vec![] }
-    }
-
-    fn mark_not_stalled(&mut self) {
-        self.stalled = false;
-    }
-
-    fn is_stalled(&self) -> bool {
-        self.stalled
+        Self { errors: vec![], completed: vec![] }
     }
 
     fn record_completed(&mut self, outcome: &Self::Obligation) {
@@ -74,6 +65,10 @@
     type Obligation = O;
     type Error = E;
 
+    fn needs_process_obligation(&self, _obligation: &Self::Obligation) -> bool {
+        true
+    }
+
     fn process_obligation(
         &mut self,
         obligation: &mut Self::Obligation,
diff --git a/compiler/rustc_data_structures/src/owning_ref/tests.rs b/compiler/rustc_data_structures/src/owning_ref/tests.rs
index 7b8179e..320c03d 100644
--- a/compiler/rustc_data_structures/src/owning_ref/tests.rs
+++ b/compiler/rustc_data_structures/src/owning_ref/tests.rs
@@ -1,3 +1,5 @@
+// FIXME: owning_ref is not sound under stacked borrows. Preferably, get rid of it.
+#[cfg(not(miri))]
 mod owning_ref {
     use super::super::OwningRef;
     use super::super::{BoxRef, Erased, ErasedBoxRef, RcRef};
@@ -361,6 +363,8 @@
     }
 }
 
+// FIXME: owning_ref is not sound under stacked borrows. Preferably, get rid of it.
+#[cfg(not(miri))]
 mod owning_ref_mut {
     use super::super::BoxRef;
     use super::super::{BoxRefMut, Erased, ErasedBoxRefMut, OwningRefMut};
diff --git a/compiler/rustc_data_structures/src/profiling.rs b/compiler/rustc_data_structures/src/profiling.rs
index bf7924a..88ff33b 100644
--- a/compiler/rustc_data_structures/src/profiling.rs
+++ b/compiler/rustc_data_structures/src/profiling.rs
@@ -195,6 +195,7 @@
         F: for<'a> FnOnce(&'a SelfProfiler) -> TimingGuard<'a>,
     {
         #[inline(never)]
+        #[cold]
         fn cold_call<F>(profiler_ref: &SelfProfilerRef, f: F) -> TimingGuard<'_>
         where
             F: for<'a> FnOnce(&'a SelfProfiler) -> TimingGuard<'a>,
@@ -203,7 +204,7 @@
             f(&**profiler)
         }
 
-        if unlikely!(self.event_filter_mask.contains(event_filter)) {
+        if self.event_filter_mask.contains(event_filter) {
             cold_call(self, f)
         } else {
             TimingGuard::none()
@@ -550,14 +551,20 @@
     pub fn new(
         output_directory: &Path,
         crate_name: Option<&str>,
-        event_filters: &Option<Vec<String>>,
+        event_filters: Option<&[String]>,
+        counter_name: &str,
     ) -> Result<SelfProfiler, Box<dyn Error + Send + Sync>> {
         fs::create_dir_all(output_directory)?;
 
         let crate_name = crate_name.unwrap_or("unknown-crate");
-        let filename = format!("{}-{}.rustc_profile", crate_name, process::id());
+        // HACK(eddyb) we need to pad the PID, strange as it may seem, as its
+        // length can behave as a source of entropy for heap addresses, when
+        // ASLR is disabled and the heap is otherwise determinic.
+        let pid: u32 = process::id();
+        let filename = format!("{}-{:07}.rustc_profile", crate_name, pid);
         let path = output_directory.join(&filename);
-        let profiler = Profiler::new(&path)?;
+        let profiler =
+            Profiler::with_counter(&path, measureme::counters::Counter::by_name(counter_name)?)?;
 
         let query_event_kind = profiler.alloc_string("Query");
         let generic_activity_event_kind = profiler.alloc_string("GenericActivity");
@@ -570,7 +577,7 @@
 
         let mut event_filter_mask = EventFilter::empty();
 
-        if let Some(ref event_filters) = *event_filters {
+        if let Some(event_filters) = event_filters {
             let mut unknown_events = vec![];
             for item in event_filters {
                 if let Some(&(_, mask)) =
diff --git a/compiler/rustc_data_structures/src/sip128.rs b/compiler/rustc_data_structures/src/sip128.rs
index abd25f4..90793a9 100644
--- a/compiler/rustc_data_structures/src/sip128.rs
+++ b/compiler/rustc_data_structures/src/sip128.rs
@@ -255,8 +255,9 @@
         // elements from spill (at most LEN - 1 bytes could have overflowed
         // into the spill). The memcpy call is optimized away because the size
         // is known. And the whole copy is optimized away for LEN == 1.
+        let dst = self.buf.as_mut_ptr() as *mut u8;
         let src = self.buf.get_unchecked(BUFFER_SPILL_INDEX) as *const _ as *const u8;
-        ptr::copy_nonoverlapping(src, self.buf.as_mut_ptr() as *mut u8, LEN - 1);
+        ptr::copy_nonoverlapping(src, dst, LEN - 1);
 
         // This function should only be called when the write fills the buffer.
         // Therefore, when LEN == 1, the new `self.nbuf` must be zero.
diff --git a/compiler/rustc_data_structures/src/sso/set.rs b/compiler/rustc_data_structures/src/sso/set.rs
index f71522d..4fda3ad 100644
--- a/compiler/rustc_data_structures/src/sso/set.rs
+++ b/compiler/rustc_data_structures/src/sso/set.rs
@@ -126,9 +126,10 @@
 
     /// Adds a value to the set.
     ///
-    /// If the set did not have this value present, `true` is returned.
+    /// Returns whether the value was newly inserted. That is:
     ///
-    /// If the set did have this value present, `false` is returned.
+    /// - If the set did not previously contain this value, `true` is returned.
+    /// - If the set already contained this value, `false` is returned.
     #[inline]
     pub fn insert(&mut self, elem: T) -> bool {
         self.map.insert(elem, ()).is_none()
diff --git a/compiler/rustc_data_structures/src/stable_hasher.rs b/compiler/rustc_data_structures/src/stable_hasher.rs
index c8bb4fc..a915a4d 100644
--- a/compiler/rustc_data_structures/src/stable_hasher.rs
+++ b/compiler/rustc_data_structures/src/stable_hasher.rs
@@ -632,10 +632,10 @@
     }
 }
 
-/// Controls what data we do or not not hash.
+/// Controls what data we do or do not hash.
 /// Whenever a `HashStable` implementation caches its
 /// result, it needs to include `HashingControls` as part
-/// of the key, to ensure that is does not produce an incorrect
+/// of the key, to ensure that it does not produce an incorrect
 /// result (for example, using a `Fingerprint` produced while
 /// hashing `Span`s when a `Fingerprint` without `Span`s is
 /// being requested)
diff --git a/compiler/rustc_data_structures/src/svh.rs b/compiler/rustc_data_structures/src/svh.rs
index 12ef286..61654b9 100644
--- a/compiler/rustc_data_structures/src/svh.rs
+++ b/compiler/rustc_data_structures/src/svh.rs
@@ -49,8 +49,8 @@
 }
 
 impl<S: Encoder> Encodable<S> for Svh {
-    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
-        s.emit_u64(self.as_u64().to_le())
+    fn encode(&self, s: &mut S) {
+        s.emit_u64(self.as_u64().to_le());
     }
 }
 
diff --git a/compiler/rustc_data_structures/src/sync.rs b/compiler/rustc_data_structures/src/sync.rs
index f99ca53..feb82cb 100644
--- a/compiler/rustc_data_structures/src/sync.rs
+++ b/compiler/rustc_data_structures/src/sync.rs
@@ -173,7 +173,7 @@
         pub use std::cell::RefMut as LockGuard;
         pub use std::cell::RefMut as MappedLockGuard;
 
-        pub use std::lazy::OnceCell;
+        pub use std::cell::OnceCell;
 
         use std::cell::RefCell as InnerRwLock;
         use std::cell::RefCell as InnerLock;
@@ -258,7 +258,7 @@
         pub use parking_lot::MutexGuard as LockGuard;
         pub use parking_lot::MappedMutexGuard as MappedLockGuard;
 
-        pub use std::lazy::SyncOnceCell as OnceCell;
+        pub use std::sync::OnceLock as OnceCell;
 
         pub use std::sync::atomic::{AtomicBool, AtomicUsize, AtomicU32, AtomicU64};
 
diff --git a/compiler/rustc_driver/Cargo.toml b/compiler/rustc_driver/Cargo.toml
index fd2ca5b..08d5d4f 100644
--- a/compiler/rustc_driver/Cargo.toml
+++ b/compiler/rustc_driver/Cargo.toml
@@ -7,8 +7,8 @@
 crate-type = ["dylib"]
 
 [dependencies]
-libc = "0.2"
 tracing = { version = "0.1.28" }
+serde_json = "1.0.59"
 rustc_log = { path = "../rustc_log" }
 rustc_middle = { path = "../rustc_middle" }
 rustc_ast_pretty = { path = "../rustc_ast_pretty" }
@@ -20,7 +20,6 @@
 rustc_hir = { path = "../rustc_hir" }
 rustc_hir_pretty = { path = "../rustc_hir_pretty" }
 rustc_metadata = { path = "../rustc_metadata" }
-rustc_const_eval = { path = "../rustc_const_eval" }
 rustc_parse = { path = "../rustc_parse" }
 rustc_plugin_impl = { path = "../rustc_plugin_impl" }
 rustc_save_analysis = { path = "../rustc_save_analysis" }
@@ -28,11 +27,13 @@
 rustc_session = { path = "../rustc_session" }
 rustc_error_codes = { path = "../rustc_error_codes" }
 rustc_interface = { path = "../rustc_interface" }
-rustc_serialize = { path = "../rustc_serialize" }
 rustc_ast = { path = "../rustc_ast" }
 rustc_span = { path = "../rustc_span" }
 rustc_typeck = { path = "../rustc_typeck" }
 
+[target.'cfg(unix)'.dependencies]
+libc = "0.2"
+
 [target.'cfg(windows)'.dependencies]
 winapi = { version = "0.3", features = ["consoleapi", "debugapi", "processenv"] }
 
diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs
index 904d6f8..caa92e7 100644
--- a/compiler/rustc_driver/src/lib.rs
+++ b/compiler/rustc_driver/src/lib.rs
@@ -5,7 +5,6 @@
 //! This API is completely unstable and subject to change.
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
-#![feature(nll)]
 #![feature(let_else)]
 #![feature(once_cell)]
 #![recursion_limit = "256"]
@@ -30,7 +29,6 @@
 use rustc_metadata::locator;
 use rustc_save_analysis as save;
 use rustc_save_analysis::DumpHandler;
-use rustc_serialize::json::ToJson;
 use rustc_session::config::{nightly_options, CG_OPTIONS, DB_OPTIONS};
 use rustc_session::config::{ErrorOutputType, Input, OutputType, PrintRequest, TrimmedDefPaths};
 use rustc_session::cstore::MetadataLoader;
@@ -40,6 +38,7 @@
 use rustc_session::{early_error, early_error_no_abort, early_warn};
 use rustc_span::source_map::{FileLoader, FileName};
 use rustc_span::symbol::sym;
+use rustc_target::json::ToJson;
 
 use std::borrow::Cow;
 use std::cmp::max;
@@ -48,11 +47,11 @@
 use std::ffi::OsString;
 use std::fs;
 use std::io::{self, Read, Write};
-use std::lazy::SyncLazy;
 use std::panic::{self, catch_unwind};
 use std::path::PathBuf;
 use std::process::{self, Command, Stdio};
 use std::str;
+use std::sync::LazyLock;
 use std::time::Instant;
 
 pub mod args;
@@ -343,10 +342,7 @@
                 return early_exit();
             }
 
-            if sess.opts.debugging_opts.parse_only
-                || sess.opts.debugging_opts.show_span.is_some()
-                || sess.opts.debugging_opts.ast_json_noexpand
-            {
+            if sess.opts.debugging_opts.parse_only || sess.opts.debugging_opts.show_span.is_some() {
                 return early_exit();
             }
 
@@ -375,7 +371,7 @@
 
             queries.global_ctxt()?;
 
-            if sess.opts.debugging_opts.no_analysis || sess.opts.debugging_opts.ast_json {
+            if sess.opts.debugging_opts.no_analysis {
                 return early_exit();
             }
 
@@ -665,7 +661,9 @@
             }
             Sysroot => println!("{}", sess.sysroot.display()),
             TargetLibdir => println!("{}", sess.target_tlib_path.dir.display()),
-            TargetSpec => println!("{}", sess.target.to_json().pretty()),
+            TargetSpec => {
+                println!("{}", serde_json::to_string_pretty(&sess.target.to_json()).unwrap());
+            }
             FileNames | CrateName => {
                 let input = input.unwrap_or_else(|| {
                     early_error(ErrorOutputType::default(), "no input file provided")
@@ -1056,13 +1054,7 @@
     }
 
     if cg_flags.iter().any(|x| *x == "passes=list") {
-        let backend_name = debug_flags.iter().find_map(|x| {
-            if x.starts_with("codegen-backend=") {
-                Some(&x["codegen-backends=".len()..])
-            } else {
-                None
-            }
-        });
+        let backend_name = debug_flags.iter().find_map(|x| x.strip_prefix("codegen-backend="));
         get_codegen_backend(&None, backend_name).print_passes();
         return None;
     }
@@ -1149,8 +1141,8 @@
     }
 }
 
-static DEFAULT_HOOK: SyncLazy<Box<dyn Fn(&panic::PanicInfo<'_>) + Sync + Send + 'static>> =
-    SyncLazy::new(|| {
+static DEFAULT_HOOK: LazyLock<Box<dyn Fn(&panic::PanicInfo<'_>) + Sync + Send + 'static>> =
+    LazyLock::new(|| {
         let hook = panic::take_hook();
         panic::set_hook(Box::new(|info| {
             // Invoke the default handler, which prints the actual panic message and optionally a backtrace
@@ -1245,7 +1237,7 @@
     if std::env::var("RUST_BACKTRACE").is_err() {
         std::env::set_var("RUST_BACKTRACE", "full");
     }
-    SyncLazy::force(&DEFAULT_HOOK);
+    LazyLock::force(&DEFAULT_HOOK);
 }
 
 /// This allows tools to enable rust logging without having to magically match rustc's
diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs
index 61a177f..d507293 100644
--- a/compiler/rustc_error_codes/src/error_codes.rs
+++ b/compiler/rustc_error_codes/src/error_codes.rs
@@ -491,6 +491,7 @@
 E0785: include_str!("./error_codes/E0785.md"),
 E0786: include_str!("./error_codes/E0786.md"),
 E0787: include_str!("./error_codes/E0787.md"),
+E0788: include_str!("./error_codes/E0788.md"),
 ;
 //  E0006, // merged with E0005
 //  E0008, // cannot bind by-move into a pattern guard
@@ -527,7 +528,7 @@
 //  E0190, // deprecated: can only cast a &-pointer to an &-object
 //  E0194, // merged into E0403
 //  E0196, // cannot determine a type for this closure
-    E0208,
+    E0208, // internal error code
 //  E0209, // builtin traits can only be implemented on structs or enums
 //  E0213, // associated types are not accepted in this context
 //  E0215, // angle-bracket notation is not stable with `Fn`
@@ -632,14 +633,14 @@
 //  E0629, // missing 'feature' (rustc_const_unstable)
 //  E0630, // rustc_const_unstable attribute must be paired with stable/unstable
            // attribute
-    E0640, // infer outlives requirements
+    E0640, // infer outlives requirements, internal error code
 //  E0645, // trait aliases not finished
 //  E0694, // an unknown tool name found in scoped attributes
 //  E0702, // replaced with a generic attribute input check
 //  E0707, // multiple elided lifetimes used in arguments of `async fn`
 //  E0709, // multiple different lifetimes used in arguments of `async fn`
-    E0711, // a feature has been declared with conflicting stability attributes
-    E0717, // rustc_promotable without stability attribute
+    E0711, // a feature has been declared with conflicting stability attributes, internal error code
+    E0717, // rustc_promotable without stability attribute, internal error code
 //  E0721, // `await` keyword
 //  E0723, // unstable feature in `const` context
 //  E0738, // Removed; errored on `#[track_caller] fn`s in `extern "Rust" { ... }`.
diff --git a/compiler/rustc_error_codes/src/error_codes/E0060.md b/compiler/rustc_error_codes/src/error_codes/E0060.md
index e6906d7..54b10c8 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0060.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0060.md
@@ -16,10 +16,10 @@
 simply calling `printf()` is invalid. But the following uses are allowed:
 
 ```
-# #![feature(static_nobundle)]
 # use std::os::raw::{c_char, c_int};
 # #[cfg_attr(all(windows, target_env = "msvc"),
-#            link(name = "legacy_stdio_definitions", kind = "static-nobundle"))]
+#            link(name = "legacy_stdio_definitions",
+#                 kind = "static", modifiers = "-bundle"))]
 # extern "C" { fn printf(_: *const c_char, ...) -> c_int; }
 # fn main() {
 unsafe {
diff --git a/compiler/rustc_error_codes/src/error_codes/E0263.md b/compiler/rustc_error_codes/src/error_codes/E0263.md
index 37271ac..2d1ac40 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0263.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0263.md
@@ -1,8 +1,10 @@
+#### Note: this error code is no longer emitted by the compiler.
+
 A lifetime was declared more than once in the same scope.
 
 Erroneous code example:
 
-```compile_fail,E0263
+```compile_fail,E0403
 fn foo<'a, 'b, 'a>(x: &'a str, y: &'b str, z: &'a str) { // error!
 }
 ```
diff --git a/compiler/rustc_error_codes/src/error_codes/E0312.md b/compiler/rustc_error_codes/src/error_codes/E0312.md
index cb090d0..c5f7cf2 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0312.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0312.md
@@ -1,8 +1,10 @@
+#### Note: this error code is no longer emitted by the compiler.
+
 Reference's lifetime of borrowed content doesn't match the expected lifetime.
 
 Erroneous code example:
 
-```compile_fail,E0312
+```compile_fail
 pub fn opt_str<'a>(maybestr: &'a Option<String>) -> &'static str {
     if maybestr.is_none() {
         "(none)"
diff --git a/compiler/rustc_error_codes/src/error_codes/E0432.md b/compiler/rustc_error_codes/src/error_codes/E0432.md
index a6e2aca..2920e26 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0432.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0432.md
@@ -10,10 +10,10 @@
 import items relative to the current and parent modules, use the `self::` and
 `super::` prefixes, respectively.
 
-In Rust 2018, paths in `use` statements are relative to the current module
-unless they begin with the name of a crate or a literal `crate::`, in which
-case they start from the crate root. As in Rust 2015 code, the `self::` and
-`super::` prefixes refer to the current and parent modules respectively.
+In Rust 2018 or later, paths in `use` statements are relative to the current
+module unless they begin with the name of a crate or a literal `crate::`, in
+which case they start from the crate root. As in Rust 2015 code, the `self::`
+and `super::` prefixes refer to the current and parent modules respectively.
 
 Also verify that you didn't misspell the import name and that the import exists
 in the module from where you tried to import it. Example:
@@ -38,8 +38,8 @@
 # fn main() {}
 ```
 
-In Rust 2018 the `extern crate` declaration is not required and you can instead
-just `use` it:
+Since Rust 2018 the `extern crate` declaration is not required and
+you can instead just `use` it:
 
 ```edition2018
 use core::any; // No extern crate required in Rust 2018.
diff --git a/compiler/rustc_error_codes/src/error_codes/E0451.md b/compiler/rustc_error_codes/src/error_codes/E0451.md
index 821073f..a12378a 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0451.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0451.md
@@ -3,14 +3,14 @@
 Erroneous code example:
 
 ```compile_fail,E0451
-mod Bar {
+mod bar {
     pub struct Foo {
         pub a: isize,
         b: isize,
     }
 }
 
-let f = Bar::Foo{ a: 0, b: 0 }; // error: field `b` of struct `Bar::Foo`
+let f = bar::Foo{ a: 0, b: 0 }; // error: field `b` of struct `bar::Foo`
                                 //        is private
 ```
 
@@ -18,20 +18,20 @@
 or implement a function for easy instantiation. Examples:
 
 ```
-mod Bar {
+mod bar {
     pub struct Foo {
         pub a: isize,
         pub b: isize, // we set `b` field public
     }
 }
 
-let f = Bar::Foo{ a: 0, b: 0 }; // ok!
+let f = bar::Foo{ a: 0, b: 0 }; // ok!
 ```
 
 Or:
 
 ```
-mod Bar {
+mod bar {
     pub struct Foo {
         pub a: isize,
         b: isize, // still private
@@ -44,5 +44,5 @@
     }
 }
 
-let f = Bar::Foo::new(); // ok!
+let f = bar::Foo::new(); // ok!
 ```
diff --git a/compiler/rustc_error_codes/src/error_codes/E0455.md b/compiler/rustc_error_codes/src/error_codes/E0455.md
index 84689b3..437daca 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0455.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0455.md
@@ -1,6 +1,11 @@
+Some linking kinds are target-specific and not supported on all platforms.
+
 Linking with `kind=framework` is only supported when targeting macOS,
 as frameworks are specific to that operating system.
 
+Similarly, `kind=raw-dylib` is only supported when targeting Windows-like
+platforms.
+
 Erroneous code example:
 
 ```ignore (should-compile_fail-but-cannot-doctest-conditionally-without-macos)
diff --git a/compiler/rustc_error_codes/src/error_codes/E0458.md b/compiler/rustc_error_codes/src/error_codes/E0458.md
index 359aeb6..1b280cb 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0458.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0458.md
@@ -12,3 +12,4 @@
 * static
 * dylib
 * framework
+* raw-dylib
diff --git a/compiler/rustc_error_codes/src/error_codes/E0477.md b/compiler/rustc_error_codes/src/error_codes/E0477.md
index 9cfefb1..c6be8dc 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0477.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0477.md
@@ -1,8 +1,10 @@
+#### Note: this error code is no longer emitted by the compiler.
+
 The type does not fulfill the required lifetime.
 
 Erroneous code example:
 
-```compile_fail,E0477
+```compile_fail
 use std::sync::Mutex;
 
 struct MyString<'a> {
diff --git a/compiler/rustc_error_codes/src/error_codes/E0495.md b/compiler/rustc_error_codes/src/error_codes/E0495.md
index f956237..cd10e71 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0495.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0495.md
@@ -1,8 +1,10 @@
+#### Note: this error code is no longer emitted by the compiler.
+
 A lifetime cannot be determined in the given situation.
 
 Erroneous code example:
 
-```compile_fail,E0495
+```compile_fail
 fn transmute_lifetime<'a, 'b, T>(t: &'a (T,)) -> &'b T {
     match (&t,) { // error!
         ((u,),) => u,
diff --git a/compiler/rustc_error_codes/src/error_codes/E0574.md b/compiler/rustc_error_codes/src/error_codes/E0574.md
index 8154d5b..4881f61 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0574.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0574.md
@@ -4,9 +4,9 @@
 Erroneous code example:
 
 ```compile_fail,E0574
-mod Mordor {}
+mod mordor {}
 
-let sauron = Mordor { x: () }; // error!
+let sauron = mordor { x: () }; // error!
 
 enum Jak {
     Daxter { i: isize },
@@ -19,17 +19,17 @@
 ```
 
 In all these errors, a type was expected. For example, in the first error,
-we tried to instantiate the `Mordor` module, which is impossible. If you want
+we tried to instantiate the `mordor` module, which is impossible. If you want
 to instantiate a type inside a module, you can do it as follow:
 
 ```
-mod Mordor {
+mod mordor {
     pub struct TheRing {
         pub x: usize,
     }
 }
 
-let sauron = Mordor::TheRing { x: 1 }; // ok!
+let sauron = mordor::TheRing { x: 1 }; // ok!
 ```
 
 In the second error, we tried to bind the `Jak` enum directly, which is not
diff --git a/compiler/rustc_error_codes/src/error_codes/E0577.md b/compiler/rustc_error_codes/src/error_codes/E0577.md
index 1feb9c0..eba2d3b 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0577.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0577.md
@@ -11,13 +11,13 @@
 ```
 
 `Sea` is not a module, therefore it is invalid to use it in a visibility path.
-To fix this error we need to ensure `Sea` is a module.
+To fix this error we need to ensure `sea` is a module.
 
 Please note that the visibility scope can only be applied on ancestors!
 
 ```edition2018
-pub mod Sea {
-    pub (in crate::Sea) struct Shark; // ok!
+pub mod sea {
+    pub (in crate::sea) struct Shark; // ok!
 }
 
 fn main() {}
diff --git a/compiler/rustc_error_codes/src/error_codes/E0603.md b/compiler/rustc_error_codes/src/error_codes/E0603.md
index 69fefce..eb29311 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0603.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0603.md
@@ -3,13 +3,13 @@
 Erroneous code example:
 
 ```compile_fail,E0603
-mod SomeModule {
+mod foo {
     const PRIVATE: u32 = 0x_a_bad_1dea_u32; // This const is private, so we
                                             // can't use it outside of the
-                                            // `SomeModule` module.
+                                            // `foo` module.
 }
 
-println!("const value: {}", SomeModule::PRIVATE); // error: constant `PRIVATE`
+println!("const value: {}", foo::PRIVATE); // error: constant `PRIVATE`
                                                   //        is private
 ```
 
@@ -17,10 +17,10 @@
 keyword. Example:
 
 ```
-mod SomeModule {
+mod foo {
     pub const PRIVATE: u32 = 0x_a_bad_1dea_u32; // We set it public by using the
                                                 // `pub` keyword.
 }
 
-println!("const value: {}", SomeModule::PRIVATE); // ok!
+println!("const value: {}", foo::PRIVATE); // ok!
 ```
diff --git a/compiler/rustc_error_codes/src/error_codes/E0623.md b/compiler/rustc_error_codes/src/error_codes/E0623.md
index 1290edd..34db641 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0623.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0623.md
@@ -3,39 +3,70 @@
 Erroneous code example:
 
 ```compile_fail,E0623
-struct Foo<'a> {
-    x: &'a isize,
-}
+struct Foo<'a, 'b, T>(std::marker::PhantomData<(&'a (), &'b (), T)>)
+where
+    T: Convert<'a, 'b>;
 
-fn bar<'short, 'long>(c: Foo<'short>, l: &'long isize) {
-    let _: Foo<'long> = c; // error!
+trait Convert<'a, 'b>: Sized {
+    fn cast(&'a self) -> &'b Self;
+}
+impl<'long: 'short, 'short, T> Convert<'long, 'short> for T {
+    fn cast(&'long self) -> &'short T {
+        self
+    }
+}
+// error
+fn badboi<'in_, 'out, T>(
+    x: Foo<'in_, 'out, T>,
+    sadness: &'in_ T
+) -> &'out T {
+    sadness.cast()
 }
 ```
 
 In this example, we tried to set a value with an incompatible lifetime to
-another one (`'long` is unrelated to `'short`). We can solve this issue in
+another one (`'in_` is unrelated to `'out`). We can solve this issue in
 two different ways:
 
-Either we make `'short` live at least as long as `'long`:
+Either we make `'in_` live at least as long as `'out`:
 
 ```
-struct Foo<'a> {
-    x: &'a isize,
-}
+struct Foo<'a, 'b, T>(std::marker::PhantomData<(&'a (), &'b (), T)>)
+where
+    T: Convert<'a, 'b>;
 
-// we set 'short to live at least as long as 'long
-fn bar<'short: 'long, 'long>(c: Foo<'short>, l: &'long isize) {
-    let _: Foo<'long> = c; // ok!
+trait Convert<'a, 'b>: Sized {
+    fn cast(&'a self) -> &'b Self;
+}
+impl<'long: 'short, 'short, T> Convert<'long, 'short> for T {
+    fn cast(&'long self) -> &'short T {
+        self
+    }
+}
+fn badboi<'in_: 'out, 'out, T>(
+    x: Foo<'in_, 'out, T>,
+    sadness: &'in_ T
+) -> &'out T {
+    sadness.cast()
 }
 ```
 
 Or we use only one lifetime:
 
 ```
-struct Foo<'a> {
-    x: &'a isize,
+struct Foo<'a, 'b, T>(std::marker::PhantomData<(&'a (), &'b (), T)>)
+where
+    T: Convert<'a, 'b>;
+
+trait Convert<'a, 'b>: Sized {
+    fn cast(&'a self) -> &'b Self;
 }
-fn bar<'short>(c: Foo<'short>, l: &'short isize) {
-    let _: Foo<'short> = c; // ok!
+impl<'long: 'short, 'short, T> Convert<'long, 'short> for T {
+    fn cast(&'long self) -> &'short T {
+        self
+    }
+}
+fn badboi<'out, T>(x: Foo<'out, 'out, T>, sadness: &'out T) -> &'out T {
+    sadness.cast()
 }
 ```
diff --git a/compiler/rustc_error_codes/src/error_codes/E0632.md b/compiler/rustc_error_codes/src/error_codes/E0632.md
index 40840e8..7e0a5c7 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0632.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0632.md
@@ -1,9 +1,11 @@
+#### Note: this error code is no longer emitted by the compiler.
+
 An explicit generic argument was provided when calling a function that
 uses `impl Trait` in argument position.
 
 Erroneous code example:
 
-```compile_fail,E0632
+```ignore (no longer an error)
 fn foo<T: Copy>(a: T, b: impl Clone) {}
 
 foo::<i32>(0i32, "abc".to_string());
diff --git a/compiler/rustc_error_codes/src/error_codes/E0713.md b/compiler/rustc_error_codes/src/error_codes/E0713.md
index 9361046..9b1b77f 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0713.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0713.md
@@ -4,8 +4,6 @@
 Erroneous code example:
 
 ```compile_fail,E0713
-#![feature(nll)]
-
 pub struct S<'a> { data: &'a mut String }
 
 impl<'a> Drop for S<'a> {
diff --git a/compiler/rustc_error_codes/src/error_codes/E0742.md b/compiler/rustc_error_codes/src/error_codes/E0742.md
index fed9f1f..e10c163 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0742.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0742.md
@@ -4,18 +4,18 @@
 Erroneous code example:
 
 ```compile_fail,E0742,edition2018
-pub mod Sea {}
+pub mod sea {}
 
-pub (in crate::Sea) struct Shark; // error!
+pub (in crate::sea) struct Shark; // error!
 
 fn main() {}
 ```
 
-To fix this error, we need to move the `Shark` struct inside the `Sea` module:
+To fix this error, we need to move the `Shark` struct inside the `sea` module:
 
 ```edition2018
-pub mod Sea {
-    pub (in crate::Sea) struct Shark; // ok!
+pub mod sea {
+    pub (in crate::sea) struct Shark; // ok!
 }
 
 fn main() {}
@@ -25,9 +25,9 @@
 ancestor:
 
 ```edition2018
-pub mod Earth {
-    pub mod Sea {
-        pub (in crate::Earth) struct Shark; // ok!
+pub mod earth {
+    pub mod sea {
+        pub (in crate::earth) struct Shark; // ok!
     }
 }
 
diff --git a/compiler/rustc_error_codes/src/error_codes/E0759.md b/compiler/rustc_error_codes/src/error_codes/E0759.md
index 6b16a7d..ce5d42b 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0759.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0759.md
@@ -1,8 +1,10 @@
+#### Note: this error code is no longer emitted by the compiler.
+
 Return type involving a trait did not require `'static` lifetime.
 
 Erroneous code examples:
 
-```compile_fail,E0759
+```compile_fail
 use std::fmt::Debug;
 
 fn foo(x: &i32) -> impl Debug { // error!
diff --git a/compiler/rustc_error_codes/src/error_codes/E0772.md b/compiler/rustc_error_codes/src/error_codes/E0772.md
index 3b73aba..5ffffd5 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0772.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0772.md
@@ -1,9 +1,11 @@
+#### Note: this error code is no longer emitted by the compiler.
+
 A trait object has some specific lifetime `'1`, but it was used in a way that
 requires it to have a `'static` lifetime.
 
 Example of erroneous code:
 
-```compile_fail,E0772
+```compile_fail
 trait BooleanLike {}
 trait Person {}
 
diff --git a/compiler/rustc_error_codes/src/error_codes/E0788.md b/compiler/rustc_error_codes/src/error_codes/E0788.md
new file mode 100644
index 0000000..d26f9b5
--- /dev/null
+++ b/compiler/rustc_error_codes/src/error_codes/E0788.md
@@ -0,0 +1,26 @@
+A `#[no_coverage]` attribute was applied to something which does not show up
+in code coverage, or is too granular to be excluded from the coverage report.
+
+For now, this attribute can only be applied to function, method, and closure
+definitions. In the future, it may be added to statements, blocks, and
+expressions, and for the time being, using this attribute in those places
+will just emit an `unused_attributes` lint instead of this error.
+
+Example of erroneous code:
+
+```compile_fail,E0788
+#[no_coverage]
+struct Foo;
+
+#[no_coverage]
+const FOO: Foo = Foo;
+```
+
+`#[no_coverage]` tells the compiler to not generate coverage instrumentation for
+a piece of code when the `-C instrument-coverage` flag is passed. Things like
+structs and consts are not coverable code, and thus cannot do anything with this
+attribute.
+
+If you wish to apply this attribute to all methods in an impl or module,
+manually annotate each method; it is not possible to annotate the entire impl
+with a `#[no_coverage]` attribute.
diff --git a/compiler/rustc_error_messages/locales/en-US/builtin_macros.ftl b/compiler/rustc_error_messages/locales/en-US/builtin_macros.ftl
new file mode 100644
index 0000000..1d3e33c
--- /dev/null
+++ b/compiler/rustc_error_messages/locales/en-US/builtin_macros.ftl
@@ -0,0 +1,5 @@
+builtin-macros-requires-cfg-pattern =
+    macro requires a cfg-pattern as an argument
+    .label = cfg-pattern required
+
+builtin-macros-expected-one-cfg-pattern = expected 1 cfg-pattern
diff --git a/compiler/rustc_error_messages/locales/en-US/parser.ftl b/compiler/rustc_error_messages/locales/en-US/parser.ftl
index 3143b81..076b1b1 100644
--- a/compiler/rustc_error_messages/locales/en-US/parser.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/parser.ftl
@@ -5,3 +5,30 @@
 parser-maybe-report-ambiguous-plus =
     ambiguous `+` in a type
     .suggestion = use parentheses to disambiguate
+
+parser-maybe-recover-from-bad-type-plus =
+    expected a path on the left-hand side of `+`, not `{$ty}`
+
+parser-add-paren = try adding parentheses
+
+parser-forgot-paren = perhaps you forgot parentheses?
+
+parser-expect-path = expected a path
+
+parser-maybe-recover-from-bad-qpath-stage-2 =
+    missing angle brackets in associated item path
+    .suggestion = try: `{$ty}`
+
+parser-incorrect-semicolon =
+    expected item, found `;`
+    .suggestion = remove this semicolon
+    .help = {$name} declarations are not followed by a semicolon
+
+parser-incorrect-use-of-await =
+    incorrect use of `await`
+    .parentheses-suggestion = `await` is not a method call, remove the parentheses
+    .postfix-suggestion = `await` is a postfix operation
+
+parser-in-in-typo =
+    expected iterable, found keyword `in`
+    .suggestion = remove the duplicated `in`
diff --git a/compiler/rustc_error_messages/locales/en-US/typeck.ftl b/compiler/rustc_error_messages/locales/en-US/typeck.ftl
index 95b348e..c61735a 100644
--- a/compiler/rustc_error_messages/locales/en-US/typeck.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/typeck.ftl
@@ -95,12 +95,6 @@
 typeck-unconstrained-opaque-type = unconstrained opaque type
     .note = `{$name}` must be used in combination with a concrete type within the same module
 
-typeck-explicit-generic-args-with-impl-trait =
-    cannot provide explicit generic arguments when `impl Trait` is used in argument position
-    .label = explicit generic argument not allowed
-    .note = see issue #83701 <https://github.com/rust-lang/rust/issues/83701> for more information
-    .help = add `#![feature(explicit_generic_args_with_impl_trait)]` to the crate attributes to enable
-
 typeck-missing-type-params =
     the type {$parameterCount ->
         [one] parameter
diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs
index e1e0ed7..7211c05 100644
--- a/compiler/rustc_error_messages/src/lib.rs
+++ b/compiler/rustc_error_messages/src/lib.rs
@@ -1,12 +1,12 @@
 #![feature(let_chains)]
 #![feature(once_cell)]
-#![feature(path_try_exists)]
+#![feature(rustc_attrs)]
 #![feature(type_alias_impl_trait)]
 
 use fluent_bundle::FluentResource;
 use fluent_syntax::parser::ParserError;
 use rustc_data_structures::sync::Lrc;
-use rustc_macros::{Decodable, Encodable};
+use rustc_macros::{fluent_messages, Decodable, Encodable};
 use rustc_span::Span;
 use std::borrow::Cow;
 use std::error::Error;
@@ -17,9 +17,9 @@
 use tracing::{instrument, trace};
 
 #[cfg(not(parallel_compiler))]
-use std::lazy::Lazy;
+use std::cell::LazyCell as Lazy;
 #[cfg(parallel_compiler)]
-use std::lazy::SyncLazy as Lazy;
+use std::sync::LazyLock as Lazy;
 
 #[cfg(parallel_compiler)]
 use intl_memoizer::concurrent::IntlLangMemoizer;
@@ -29,8 +29,14 @@
 pub use fluent_bundle::{FluentArgs, FluentError, FluentValue};
 pub use unic_langid::{langid, LanguageIdentifier};
 
-pub static DEFAULT_LOCALE_RESOURCES: &'static [&'static str] =
-    &[include_str!("../locales/en-US/typeck.ftl"), include_str!("../locales/en-US/parser.ftl")];
+// Generates `DEFAULT_LOCALE_RESOURCES` static and `fluent_generated` module.
+fluent_messages! {
+    parser => "../locales/en-US/parser.ftl",
+    typeck => "../locales/en-US/typeck.ftl",
+    builtin_macros => "../locales/en-US/builtin_macros.ftl",
+}
+
+pub use fluent_generated::{self as fluent, DEFAULT_LOCALE_RESOURCES};
 
 pub type FluentBundle = fluent_bundle::bundle::FluentBundle<FluentResource, IntlLangMemoizer>;
 
@@ -229,11 +235,55 @@
 /// Identifier for the Fluent message/attribute corresponding to a diagnostic message.
 type FluentId = Cow<'static, str>;
 
+/// Abstraction over a message in a subdiagnostic (i.e. label, note, help, etc) to support both
+/// translatable and non-translatable diagnostic messages.
+///
+/// Translatable messages for subdiagnostics are typically attributes attached to a larger Fluent
+/// message so messages of this type must be combined with a `DiagnosticMessage` (using
+/// `DiagnosticMessage::with_subdiagnostic_message`) before rendering. However, subdiagnostics from
+/// the `SessionSubdiagnostic` derive refer to Fluent identifiers directly.
+#[rustc_diagnostic_item = "SubdiagnosticMessage"]
+pub enum SubdiagnosticMessage {
+    /// Non-translatable diagnostic message.
+    // FIXME(davidtwco): can a `Cow<'static, str>` be used here?
+    Str(String),
+    /// Identifier of a Fluent message. Instances of this variant are generated by the
+    /// `SessionSubdiagnostic` derive.
+    FluentIdentifier(FluentId),
+    /// Attribute of a Fluent message. Needs to be combined with a Fluent identifier to produce an
+    /// actual translated message. Instances of this variant are generated by the `fluent_messages`
+    /// macro.
+    ///
+    /// <https://projectfluent.org/fluent/guide/attributes.html>
+    FluentAttr(FluentId),
+}
+
+impl SubdiagnosticMessage {
+    /// Create a `SubdiagnosticMessage` for the provided Fluent attribute.
+    pub fn attr(id: impl Into<FluentId>) -> Self {
+        SubdiagnosticMessage::FluentAttr(id.into())
+    }
+
+    /// Create a `SubdiagnosticMessage` for the provided Fluent identifier.
+    pub fn message(id: impl Into<FluentId>) -> Self {
+        SubdiagnosticMessage::FluentIdentifier(id.into())
+    }
+}
+
+/// `From` impl that enables existing diagnostic calls to functions which now take
+/// `impl Into<SubdiagnosticMessage>` to continue to work as before.
+impl<S: Into<String>> From<S> for SubdiagnosticMessage {
+    fn from(s: S) -> Self {
+        SubdiagnosticMessage::Str(s.into())
+    }
+}
+
 /// Abstraction over a message in a diagnostic to support both translatable and non-translatable
 /// diagnostic messages.
 ///
 /// Intended to be removed once diagnostics are entirely translatable.
 #[derive(Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable)]
+#[rustc_diagnostic_item = "DiagnosticMessage"]
 pub enum DiagnosticMessage {
     /// Non-translatable diagnostic message.
     // FIXME(davidtwco): can a `Cow<'static, str>` be used here?
@@ -247,6 +297,29 @@
 }
 
 impl DiagnosticMessage {
+    /// Given a `SubdiagnosticMessage` which may contain a Fluent attribute, create a new
+    /// `DiagnosticMessage` that combines that attribute with the Fluent identifier of `self`.
+    ///
+    /// - If the `SubdiagnosticMessage` is non-translatable then return the message as a
+    /// `DiagnosticMessage`.
+    /// - If `self` is non-translatable then return `self`'s message.
+    pub fn with_subdiagnostic_message(&self, sub: SubdiagnosticMessage) -> Self {
+        let attr = match sub {
+            SubdiagnosticMessage::Str(s) => return DiagnosticMessage::Str(s.clone()),
+            SubdiagnosticMessage::FluentIdentifier(id) => {
+                return DiagnosticMessage::FluentIdentifier(id, None);
+            }
+            SubdiagnosticMessage::FluentAttr(attr) => attr,
+        };
+
+        match self {
+            DiagnosticMessage::Str(s) => DiagnosticMessage::Str(s.clone()),
+            DiagnosticMessage::FluentIdentifier(id, _) => {
+                DiagnosticMessage::FluentIdentifier(id.clone(), Some(attr))
+            }
+        }
+    }
+
     /// Returns the `String` contained within the `DiagnosticMessage::Str` variant, assuming that
     /// this diagnostic message is of the legacy, non-translatable variety. Panics if this
     /// assumption does not hold.
@@ -261,14 +334,9 @@
     }
 
     /// Create a `DiagnosticMessage` for the provided Fluent identifier.
-    pub fn fluent(id: impl Into<FluentId>) -> Self {
+    pub fn new(id: impl Into<FluentId>) -> Self {
         DiagnosticMessage::FluentIdentifier(id.into(), None)
     }
-
-    /// Create a `DiagnosticMessage` for the provided Fluent identifier and attribute.
-    pub fn fluent_attr(id: impl Into<FluentId>, attr: impl Into<FluentId>) -> Self {
-        DiagnosticMessage::FluentIdentifier(id.into(), Some(attr.into()))
-    }
 }
 
 /// `From` impl that enables existing diagnostic calls to functions which now take
diff --git a/compiler/rustc_errors/Cargo.toml b/compiler/rustc_errors/Cargo.toml
index 5f91998..8955762 100644
--- a/compiler/rustc_errors/Cargo.toml
+++ b/compiler/rustc_errors/Cargo.toml
@@ -19,6 +19,8 @@
 termcolor = "1.0"
 annotate-snippets = "0.8.0"
 termize = "0.1.1"
+serde = { version = "1.0.125", features = ["derive"] }
+serde_json = "1.0.59"
 
 [target.'cfg(windows)'.dependencies]
 winapi = { version = "0.3", features = ["handleapi", "synchapi", "winbase"] }
diff --git a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs
index 1f270fc..0fcd61d 100644
--- a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs
+++ b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs
@@ -87,7 +87,7 @@
         Level::Bug | Level::DelayedBug | Level::Fatal | Level::Error { .. } => {
             AnnotationType::Error
         }
-        Level::Warning => AnnotationType::Warning,
+        Level::Warning(_) => AnnotationType::Warning,
         Level::Note | Level::OnceNote => AnnotationType::Note,
         Level::Help => AnnotationType::Help,
         // FIXME(#59346): Not sure how to map this level
diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs
index 909ed56..b854513 100644
--- a/compiler/rustc_errors/src/diagnostic.rs
+++ b/compiler/rustc_errors/src/diagnostic.rs
@@ -1,7 +1,7 @@
 use crate::snippet::Style;
 use crate::{
-    CodeSuggestion, DiagnosticMessage, Level, MultiSpan, Substitution, SubstitutionPart,
-    SuggestionStyle,
+    CodeSuggestion, DiagnosticMessage, Level, MultiSpan, SubdiagnosticMessage, Substitution,
+    SubstitutionPart, SuggestionStyle,
 };
 use rustc_data_structures::stable_map::FxHashMap;
 use rustc_error_messages::FluentValue;
@@ -80,6 +80,7 @@
 
 /// Trait implemented by error types. This should not be implemented manually. Instead, use
 /// `#[derive(SessionSubdiagnostic)]` -- see [rustc_macros::SessionSubdiagnostic].
+#[rustc_diagnostic_item = "AddSubdiagnostic"]
 pub trait AddSubdiagnostic {
     /// Add a subdiagnostic to an existing diagnostic.
     fn add_to_diagnostic(self, diag: &mut Diagnostic);
@@ -90,7 +91,7 @@
 pub struct Diagnostic {
     // NOTE(eddyb) this is private to disallow arbitrary after-the-fact changes,
     // outside of what methods in this crate themselves allow.
-    crate level: Level,
+    pub(crate) level: Level,
 
     pub message: Vec<(DiagnosticMessage, Style)>,
     pub code: Option<DiagnosticId>,
@@ -208,7 +209,7 @@
             | Level::Error { .. }
             | Level::FailureNote => true,
 
-            Level::Warning
+            Level::Warning(_)
             | Level::Note
             | Level::OnceNote
             | Level::Help
@@ -221,7 +222,9 @@
         &mut self,
         unstable_to_stable: &FxHashMap<LintExpectationId, LintExpectationId>,
     ) {
-        if let Level::Expect(expectation_id) = &mut self.level {
+        if let Level::Expect(expectation_id) | Level::Warning(Some(expectation_id)) =
+            &mut self.level
+        {
             if expectation_id.is_stable() {
                 return;
             }
@@ -283,8 +286,9 @@
     ///
     /// This span is *not* considered a ["primary span"][`MultiSpan`]; only
     /// the `Span` supplied when creating the diagnostic is primary.
-    pub fn span_label(&mut self, span: Span, label: impl Into<DiagnosticMessage>) -> &mut Self {
-        self.span.push_span_label(span, label.into());
+    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
+    pub fn span_label(&mut self, span: Span, label: impl Into<SubdiagnosticMessage>) -> &mut Self {
+        self.span.push_span_label(span, self.subdiagnostic_message_to_diagnostic_message(label));
         self
     }
 
@@ -401,12 +405,13 @@
     }
 
     /// Add a note attached to this diagnostic.
-    pub fn note(&mut self, msg: impl Into<DiagnosticMessage>) -> &mut Self {
+    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
+    pub fn note(&mut self, msg: impl Into<SubdiagnosticMessage>) -> &mut Self {
         self.sub(Level::Note, msg, MultiSpan::new(), None);
         self
     }
 
-    pub fn highlighted_note<M: Into<DiagnosticMessage>>(
+    pub fn highlighted_note<M: Into<SubdiagnosticMessage>>(
         &mut self,
         msg: Vec<(M, Style)>,
     ) -> &mut Self {
@@ -416,17 +421,18 @@
 
     /// Prints the span with a note above it.
     /// This is like [`Diagnostic::note()`], but it gets its own span.
-    pub fn note_once(&mut self, msg: impl Into<DiagnosticMessage>) -> &mut Self {
+    pub fn note_once(&mut self, msg: impl Into<SubdiagnosticMessage>) -> &mut Self {
         self.sub(Level::OnceNote, msg, MultiSpan::new(), None);
         self
     }
 
     /// Prints the span with a note above it.
     /// This is like [`Diagnostic::note()`], but it gets its own span.
+    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
     pub fn span_note<S: Into<MultiSpan>>(
         &mut self,
         sp: S,
-        msg: impl Into<DiagnosticMessage>,
+        msg: impl Into<SubdiagnosticMessage>,
     ) -> &mut Self {
         self.sub(Level::Note, msg, sp.into(), None);
         self
@@ -437,31 +443,34 @@
     pub fn span_note_once<S: Into<MultiSpan>>(
         &mut self,
         sp: S,
-        msg: impl Into<DiagnosticMessage>,
+        msg: impl Into<SubdiagnosticMessage>,
     ) -> &mut Self {
         self.sub(Level::OnceNote, msg, sp.into(), None);
         self
     }
 
     /// Add a warning attached to this diagnostic.
-    pub fn warn(&mut self, msg: impl Into<DiagnosticMessage>) -> &mut Self {
-        self.sub(Level::Warning, msg, MultiSpan::new(), None);
+    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
+    pub fn warn(&mut self, msg: impl Into<SubdiagnosticMessage>) -> &mut Self {
+        self.sub(Level::Warning(None), msg, MultiSpan::new(), None);
         self
     }
 
     /// Prints the span with a warning above it.
     /// This is like [`Diagnostic::warn()`], but it gets its own span.
+    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
     pub fn span_warn<S: Into<MultiSpan>>(
         &mut self,
         sp: S,
-        msg: impl Into<DiagnosticMessage>,
+        msg: impl Into<SubdiagnosticMessage>,
     ) -> &mut Self {
-        self.sub(Level::Warning, msg, sp.into(), None);
+        self.sub(Level::Warning(None), msg, sp.into(), None);
         self
     }
 
     /// Add a help message attached to this diagnostic.
-    pub fn help(&mut self, msg: impl Into<DiagnosticMessage>) -> &mut Self {
+    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
+    pub fn help(&mut self, msg: impl Into<SubdiagnosticMessage>) -> &mut Self {
         self.sub(Level::Help, msg, MultiSpan::new(), None);
         self
     }
@@ -474,10 +483,11 @@
 
     /// Prints the span with some help above it.
     /// This is like [`Diagnostic::help()`], but it gets its own span.
+    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
     pub fn span_help<S: Into<MultiSpan>>(
         &mut self,
         sp: S,
-        msg: impl Into<DiagnosticMessage>,
+        msg: impl Into<SubdiagnosticMessage>,
     ) -> &mut Self {
         self.sub(Level::Help, msg, sp.into(), None);
         self
@@ -514,7 +524,7 @@
     /// In other words, multiple changes need to be applied as part of this suggestion.
     pub fn multipart_suggestion(
         &mut self,
-        msg: impl Into<DiagnosticMessage>,
+        msg: impl Into<SubdiagnosticMessage>,
         suggestion: Vec<(Span, String)>,
         applicability: Applicability,
     ) -> &mut Self {
@@ -530,7 +540,7 @@
     /// In other words, multiple changes need to be applied as part of this suggestion.
     pub fn multipart_suggestion_verbose(
         &mut self,
-        msg: impl Into<DiagnosticMessage>,
+        msg: impl Into<SubdiagnosticMessage>,
         suggestion: Vec<(Span, String)>,
         applicability: Applicability,
     ) -> &mut Self {
@@ -544,7 +554,7 @@
     /// [`Diagnostic::multipart_suggestion()`] but you can set the [`SuggestionStyle`].
     pub fn multipart_suggestion_with_style(
         &mut self,
-        msg: impl Into<DiagnosticMessage>,
+        msg: impl Into<SubdiagnosticMessage>,
         suggestion: Vec<(Span, String)>,
         applicability: Applicability,
         style: SuggestionStyle,
@@ -557,7 +567,7 @@
                     .map(|(span, snippet)| SubstitutionPart { snippet, span })
                     .collect(),
             }],
-            msg: msg.into(),
+            msg: self.subdiagnostic_message_to_diagnostic_message(msg),
             style,
             applicability,
         });
@@ -572,7 +582,7 @@
     /// improve understandability.
     pub fn tool_only_multipart_suggestion(
         &mut self,
-        msg: impl Into<DiagnosticMessage>,
+        msg: impl Into<SubdiagnosticMessage>,
         suggestion: Vec<(Span, String)>,
         applicability: Applicability,
     ) -> &mut Self {
@@ -584,7 +594,7 @@
                     .map(|(span, snippet)| SubstitutionPart { snippet, span })
                     .collect(),
             }],
-            msg: msg.into(),
+            msg: self.subdiagnostic_message_to_diagnostic_message(msg),
             style: SuggestionStyle::CompletelyHidden,
             applicability,
         });
@@ -611,7 +621,7 @@
     pub fn span_suggestion(
         &mut self,
         sp: Span,
-        msg: impl Into<DiagnosticMessage>,
+        msg: impl Into<SubdiagnosticMessage>,
         suggestion: impl ToString,
         applicability: Applicability,
     ) -> &mut Self {
@@ -629,7 +639,7 @@
     pub fn span_suggestion_with_style(
         &mut self,
         sp: Span,
-        msg: impl Into<DiagnosticMessage>,
+        msg: impl Into<SubdiagnosticMessage>,
         suggestion: impl ToString,
         applicability: Applicability,
         style: SuggestionStyle,
@@ -638,7 +648,7 @@
             substitutions: vec![Substitution {
                 parts: vec![SubstitutionPart { snippet: suggestion.to_string(), span: sp }],
             }],
-            msg: msg.into(),
+            msg: self.subdiagnostic_message_to_diagnostic_message(msg),
             style,
             applicability,
         });
@@ -649,7 +659,7 @@
     pub fn span_suggestion_verbose(
         &mut self,
         sp: Span,
-        msg: impl Into<DiagnosticMessage>,
+        msg: impl Into<SubdiagnosticMessage>,
         suggestion: impl ToString,
         applicability: Applicability,
     ) -> &mut Self {
@@ -668,7 +678,7 @@
     pub fn span_suggestions(
         &mut self,
         sp: Span,
-        msg: impl Into<DiagnosticMessage>,
+        msg: impl Into<SubdiagnosticMessage>,
         suggestions: impl Iterator<Item = String>,
         applicability: Applicability,
     ) -> &mut Self {
@@ -680,7 +690,7 @@
             .collect();
         self.push_suggestion(CodeSuggestion {
             substitutions,
-            msg: msg.into(),
+            msg: self.subdiagnostic_message_to_diagnostic_message(msg),
             style: SuggestionStyle::ShowCode,
             applicability,
         });
@@ -691,7 +701,7 @@
     /// See also [`Diagnostic::span_suggestion()`].
     pub fn multipart_suggestions(
         &mut self,
-        msg: impl Into<DiagnosticMessage>,
+        msg: impl Into<SubdiagnosticMessage>,
         suggestions: impl Iterator<Item = Vec<(Span, String)>>,
         applicability: Applicability,
     ) -> &mut Self {
@@ -704,7 +714,7 @@
                         .collect(),
                 })
                 .collect(),
-            msg: msg.into(),
+            msg: self.subdiagnostic_message_to_diagnostic_message(msg),
             style: SuggestionStyle::ShowCode,
             applicability,
         });
@@ -717,7 +727,7 @@
     pub fn span_suggestion_short(
         &mut self,
         sp: Span,
-        msg: impl Into<DiagnosticMessage>,
+        msg: impl Into<SubdiagnosticMessage>,
         suggestion: impl ToString,
         applicability: Applicability,
     ) -> &mut Self {
@@ -740,7 +750,7 @@
     pub fn span_suggestion_hidden(
         &mut self,
         sp: Span,
-        msg: impl Into<DiagnosticMessage>,
+        msg: impl Into<SubdiagnosticMessage>,
         suggestion: impl ToString,
         applicability: Applicability,
     ) -> &mut Self {
@@ -761,7 +771,7 @@
     pub fn tool_only_span_suggestion(
         &mut self,
         sp: Span,
-        msg: impl Into<DiagnosticMessage>,
+        msg: impl Into<SubdiagnosticMessage>,
         suggestion: impl ToString,
         applicability: Applicability,
     ) -> &mut Self {
@@ -827,10 +837,22 @@
         self
     }
 
-    pub fn styled_message(&self) -> &Vec<(DiagnosticMessage, Style)> {
+    pub fn styled_message(&self) -> &[(DiagnosticMessage, Style)] {
         &self.message
     }
 
+    /// Helper function that takes a `SubdiagnosticMessage` and returns a `DiagnosticMessage` by
+    /// combining it with the primary message of the diagnostic (if translatable, otherwise it just
+    /// passes the user's string along).
+    fn subdiagnostic_message_to_diagnostic_message(
+        &self,
+        attr: impl Into<SubdiagnosticMessage>,
+    ) -> DiagnosticMessage {
+        let msg =
+            self.message.iter().map(|(msg, _)| msg).next().expect("diagnostic with no messages");
+        msg.with_subdiagnostic_message(attr.into())
+    }
+
     /// Convenience function for internal use, clients should use one of the
     /// public methods above.
     ///
@@ -838,13 +860,16 @@
     pub fn sub(
         &mut self,
         level: Level,
-        message: impl Into<DiagnosticMessage>,
+        message: impl Into<SubdiagnosticMessage>,
         span: MultiSpan,
         render_span: Option<MultiSpan>,
     ) {
         let sub = SubDiagnostic {
             level,
-            message: vec![(message.into(), Style::NoStyle)],
+            message: vec![(
+                self.subdiagnostic_message_to_diagnostic_message(message),
+                Style::NoStyle,
+            )],
             span,
             render_span,
         };
@@ -853,14 +878,17 @@
 
     /// Convenience function for internal use, clients should use one of the
     /// public methods above.
-    fn sub_with_highlights<M: Into<DiagnosticMessage>>(
+    fn sub_with_highlights<M: Into<SubdiagnosticMessage>>(
         &mut self,
         level: Level,
         mut message: Vec<(M, Style)>,
         span: MultiSpan,
         render_span: Option<MultiSpan>,
     ) {
-        let message = message.drain(..).map(|m| (m.0.into(), m.1)).collect();
+        let message = message
+            .drain(..)
+            .map(|m| (self.subdiagnostic_message_to_diagnostic_message(m.0), m.1))
+            .collect();
         let sub = SubDiagnostic { level, message, span, render_span };
         self.children.push(sub);
     }
@@ -870,11 +898,11 @@
         &self,
     ) -> (
         &Level,
-        &Vec<(DiagnosticMessage, Style)>,
+        &[(DiagnosticMessage, Style)],
         &Option<DiagnosticId>,
         &MultiSpan,
         &Result<Vec<CodeSuggestion>, SuggestionsDisabled>,
-        Option<&Vec<SubDiagnostic>>,
+        Option<&[SubDiagnostic]>,
     ) {
         (
             &self.level,
diff --git a/compiler/rustc_errors/src/diagnostic_builder.rs b/compiler/rustc_errors/src/diagnostic_builder.rs
index 53ad6e5..9e0a998 100644
--- a/compiler/rustc_errors/src/diagnostic_builder.rs
+++ b/compiler/rustc_errors/src/diagnostic_builder.rs
@@ -1,5 +1,8 @@
 use crate::diagnostic::IntoDiagnosticArg;
-use crate::{Diagnostic, DiagnosticId, DiagnosticMessage, DiagnosticStyledString, ErrorGuaranteed};
+use crate::{
+    Diagnostic, DiagnosticId, DiagnosticMessage, DiagnosticStyledString, ErrorGuaranteed,
+    SubdiagnosticMessage,
+};
 use crate::{Handler, Level, MultiSpan, StashKey};
 use rustc_lint_defs::Applicability;
 
@@ -88,7 +91,7 @@
     use crate::Level;
 
     /// Sealed helper trait for statically checking that a `Level` is an error.
-    crate trait IsError<const L: Level> {}
+    pub(crate) trait IsError<const L: Level> {}
 
     impl IsError<{ Level::Bug }> for () {}
     impl IsError<{ Level::DelayedBug }> for () {}
@@ -101,7 +104,7 @@
 impl<'a> DiagnosticBuilder<'a, ErrorGuaranteed> {
     /// Convenience function for internal use, clients should use one of the
     /// `struct_*` methods on [`Handler`].
-    crate fn new_guaranteeing_error<M: Into<DiagnosticMessage>, const L: Level>(
+    pub(crate) fn new_guaranteeing_error<M: Into<DiagnosticMessage>, const L: Level>(
         handler: &'a Handler,
         message: M,
     ) -> Self
@@ -168,7 +171,7 @@
 impl<'a> DiagnosticBuilder<'a, ()> {
     /// Convenience function for internal use, clients should use one of the
     /// `struct_*` methods on [`Handler`].
-    crate fn new<M: Into<DiagnosticMessage>>(
+    pub(crate) fn new<M: Into<DiagnosticMessage>>(
         handler: &'a Handler,
         level: Level,
         message: M,
@@ -179,7 +182,7 @@
 
     /// Creates a new `DiagnosticBuilder` with an already constructed
     /// diagnostic.
-    crate fn new_diagnostic(handler: &'a Handler, diagnostic: Diagnostic) -> Self {
+    pub(crate) fn new_diagnostic(handler: &'a Handler, diagnostic: Diagnostic) -> Self {
         debug!("Created new diagnostic");
         Self {
             inner: DiagnosticBuilderInner {
@@ -210,14 +213,14 @@
 impl<'a> DiagnosticBuilder<'a, !> {
     /// Convenience function for internal use, clients should use one of the
     /// `struct_*` methods on [`Handler`].
-    crate fn new_fatal(handler: &'a Handler, message: impl Into<DiagnosticMessage>) -> Self {
+    pub(crate) fn new_fatal(handler: &'a Handler, message: impl Into<DiagnosticMessage>) -> Self {
         let diagnostic = Diagnostic::new_with_code(Level::Fatal, None, message);
         Self::new_diagnostic_fatal(handler, diagnostic)
     }
 
     /// Creates a new `DiagnosticBuilder` with an already constructed
     /// diagnostic.
-    crate fn new_diagnostic_fatal(handler: &'a Handler, diagnostic: Diagnostic) -> Self {
+    pub(crate) fn new_diagnostic_fatal(handler: &'a Handler, diagnostic: Diagnostic) -> Self {
         debug!("Created new diagnostic");
         Self {
             inner: DiagnosticBuilderInner {
@@ -395,7 +398,7 @@
     /// the diagnostic was constructed. However, the label span is *not* considered a
     /// ["primary span"][`MultiSpan`]; only the `Span` supplied when creating the diagnostic is
     /// primary.
-    pub fn span_label(&mut self, span: Span, label: impl Into<DiagnosticMessage>) -> &mut Self);
+    pub fn span_label(&mut self, span: Span, label: impl Into<SubdiagnosticMessage>) -> &mut Self);
 
     forward!(
     /// Labels all the given spans with the provided label.
@@ -430,25 +433,29 @@
         found: DiagnosticStyledString,
     ) -> &mut Self);
 
-    forward!(pub fn note(&mut self, msg: impl Into<DiagnosticMessage>) -> &mut Self);
-    forward!(pub fn note_once(&mut self, msg: impl Into<DiagnosticMessage>) -> &mut Self);
+    forward!(pub fn note(&mut self, msg: impl Into<SubdiagnosticMessage>) -> &mut Self);
+    forward!(pub fn note_once(&mut self, msg: impl Into<SubdiagnosticMessage>) -> &mut Self);
     forward!(pub fn span_note(
         &mut self,
         sp: impl Into<MultiSpan>,
-        msg: impl Into<DiagnosticMessage>,
+        msg: impl Into<SubdiagnosticMessage>,
     ) -> &mut Self);
     forward!(pub fn span_note_once(
         &mut self,
         sp: impl Into<MultiSpan>,
-        msg: impl Into<DiagnosticMessage>,
+        msg: impl Into<SubdiagnosticMessage>,
     ) -> &mut Self);
-    forward!(pub fn warn(&mut self, msg: impl Into<DiagnosticMessage>) -> &mut Self);
-    forward!(pub fn span_warn(&mut self, sp: impl Into<MultiSpan>, msg: &str) -> &mut Self);
-    forward!(pub fn help(&mut self, msg: impl Into<DiagnosticMessage>) -> &mut Self);
+    forward!(pub fn warn(&mut self, msg: impl Into<SubdiagnosticMessage>) -> &mut Self);
+    forward!(pub fn span_warn(
+        &mut self,
+        sp: impl Into<MultiSpan>,
+        msg: impl Into<SubdiagnosticMessage>,
+    ) -> &mut Self);
+    forward!(pub fn help(&mut self, msg: impl Into<SubdiagnosticMessage>) -> &mut Self);
     forward!(pub fn span_help(
         &mut self,
         sp: impl Into<MultiSpan>,
-        msg: impl Into<DiagnosticMessage>,
+        msg: impl Into<SubdiagnosticMessage>,
     ) -> &mut Self);
     forward!(pub fn help_use_latest_edition(&mut self,) -> &mut Self);
     forward!(pub fn set_is_lint(&mut self,) -> &mut Self);
@@ -457,67 +464,67 @@
 
     forward!(pub fn multipart_suggestion(
         &mut self,
-        msg: impl Into<DiagnosticMessage>,
+        msg: impl Into<SubdiagnosticMessage>,
         suggestion: Vec<(Span, String)>,
         applicability: Applicability,
     ) -> &mut Self);
     forward!(pub fn multipart_suggestion_verbose(
         &mut self,
-        msg: impl Into<DiagnosticMessage>,
+        msg: impl Into<SubdiagnosticMessage>,
         suggestion: Vec<(Span, String)>,
         applicability: Applicability,
     ) -> &mut Self);
     forward!(pub fn tool_only_multipart_suggestion(
         &mut self,
-        msg: impl Into<DiagnosticMessage>,
+        msg: impl Into<SubdiagnosticMessage>,
         suggestion: Vec<(Span, String)>,
         applicability: Applicability,
     ) -> &mut Self);
     forward!(pub fn span_suggestion(
         &mut self,
         sp: Span,
-        msg: impl Into<DiagnosticMessage>,
+        msg: impl Into<SubdiagnosticMessage>,
         suggestion: impl ToString,
         applicability: Applicability,
     ) -> &mut Self);
     forward!(pub fn span_suggestions(
         &mut self,
         sp: Span,
-        msg: impl Into<DiagnosticMessage>,
+        msg: impl Into<SubdiagnosticMessage>,
         suggestions: impl Iterator<Item = String>,
         applicability: Applicability,
     ) -> &mut Self);
     forward!(pub fn multipart_suggestions(
         &mut self,
-        msg: impl Into<DiagnosticMessage>,
+        msg: impl Into<SubdiagnosticMessage>,
         suggestions: impl Iterator<Item = Vec<(Span, String)>>,
         applicability: Applicability,
     ) -> &mut Self);
     forward!(pub fn span_suggestion_short(
         &mut self,
         sp: Span,
-        msg: impl Into<DiagnosticMessage>,
+        msg: impl Into<SubdiagnosticMessage>,
         suggestion: impl ToString,
         applicability: Applicability,
     ) -> &mut Self);
     forward!(pub fn span_suggestion_verbose(
         &mut self,
         sp: Span,
-        msg: impl Into<DiagnosticMessage>,
+        msg: impl Into<SubdiagnosticMessage>,
         suggestion: impl ToString,
         applicability: Applicability,
     ) -> &mut Self);
     forward!(pub fn span_suggestion_hidden(
         &mut self,
         sp: Span,
-        msg: impl Into<DiagnosticMessage>,
+        msg: impl Into<SubdiagnosticMessage>,
         suggestion: impl ToString,
         applicability: Applicability,
     ) -> &mut Self);
     forward!(pub fn tool_only_span_suggestion(
         &mut self,
         sp: Span,
-        msg: impl Into<DiagnosticMessage>,
+        msg: impl Into<SubdiagnosticMessage>,
         suggestion: impl ToString,
         applicability: Applicability,
     ) -> &mut Self);
diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs
index 5dd743e..a4cbc73 100644
--- a/compiler/rustc_errors/src/emitter.rs
+++ b/compiler/rustc_errors/src/emitter.rs
@@ -10,7 +10,7 @@
 use Destination::*;
 
 use rustc_span::source_map::SourceMap;
-use rustc_span::{SourceFile, Span};
+use rustc_span::{FileLines, SourceFile, Span};
 
 use crate::snippet::{Annotation, AnnotationType, Line, MultilineAnnotation, Style, StyledString};
 use crate::styled_buffer::StyledBuffer;
@@ -771,8 +771,12 @@
         self
     }
 
-    fn maybe_anonymized(&self, line_num: usize) -> String {
-        if self.ui_testing { ANONYMIZED_LINE_NUM.to_string() } else { line_num.to_string() }
+    fn maybe_anonymized(&self, line_num: usize) -> Cow<'static, str> {
+        if self.ui_testing {
+            Cow::Borrowed(ANONYMIZED_LINE_NUM)
+        } else {
+            Cow::Owned(line_num.to_string())
+        }
     }
 
     fn draw_line(
@@ -819,7 +823,7 @@
         }
         buffer.puts(line_offset, 0, &self.maybe_anonymized(line_index), Style::LineNumber);
 
-        draw_col_separator(buffer, line_offset, width_offset - 2);
+        draw_col_separator_no_space(buffer, line_offset, width_offset - 2);
     }
 
     fn render_source_line(
@@ -1261,16 +1265,23 @@
             return 0;
         };
 
+        let will_be_emitted = |span: Span| {
+            !span.is_dummy() && {
+                let file = sm.lookup_source_file(span.hi());
+                sm.ensure_source_file_source_present(file)
+            }
+        };
+
         let mut max = 0;
         for primary_span in msp.primary_spans() {
-            if !primary_span.is_dummy() {
+            if will_be_emitted(*primary_span) {
                 let hi = sm.lookup_char_pos(primary_span.hi());
                 max = (hi.line).max(max);
             }
         }
         if !self.short_message {
             for span_label in msp.span_labels() {
-                if !span_label.span.is_dummy() {
+                if will_be_emitted(span_label.span) {
                     let hi = sm.lookup_char_pos(span_label.span.hi());
                     max = (hi.line).max(max);
                 }
@@ -1708,6 +1719,7 @@
 
     fn emit_suggestion_default(
         &mut self,
+        span: &MultiSpan,
         suggestion: &CodeSuggestion,
         args: &FluentArgs<'_>,
         level: &Level,
@@ -1753,12 +1765,30 @@
             let has_deletion = parts.iter().any(|p| p.is_deletion());
             let is_multiline = complete.lines().count() > 1;
 
-            enum DisplaySuggestion {
-                Underline,
-                Diff,
-                None,
+            if let Some(span) = span.primary_span() {
+                // Compare the primary span of the diagnostic with the span of the suggestion
+                // being emitted.  If they belong to the same file, we don't *need* to show the
+                // file name, saving in verbosity, but if it *isn't* we do need it, otherwise we're
+                // telling users to make a change but not clarifying *where*.
+                let loc = sm.lookup_char_pos(parts[0].span.lo());
+                if loc.file.name != sm.span_to_filename(span) && loc.file.name.is_real() {
+                    buffer.puts(row_num - 1, 0, "--> ", Style::LineNumber);
+                    buffer.append(
+                        row_num - 1,
+                        &format!(
+                            "{}:{}:{}",
+                            sm.filename_for_diagnostics(&loc.file.name),
+                            sm.doctest_offset_line(&loc.file.name, loc.line),
+                            loc.col.0 + 1,
+                        ),
+                        Style::LineAndColumn,
+                    );
+                    for _ in 0..max_line_num_len {
+                        buffer.prepend(row_num - 1, " ", Style::NoStyle);
+                    }
+                    row_num += 1;
+                }
             }
-
             let show_code_change = if has_deletion && !is_multiline {
                 DisplaySuggestion::Diff
             } else if (parts.len() != 1 || parts[0].snippet.trim() != complete.trim())
@@ -1780,7 +1810,7 @@
             assert!(!file_lines.lines.is_empty() || parts[0].span.is_dummy());
 
             let line_start = sm.lookup_char_pos(parts[0].span.lo()).line;
-            draw_col_separator_no_space(&mut buffer, 1, max_line_num_len + 1);
+            draw_col_separator_no_space(&mut buffer, row_num - 1, max_line_num_len + 1);
             let mut lines = complete.lines();
             if lines.clone().next().is_none() {
                 // Account for a suggestion to completely remove a line(s) with whitespace (#94192).
@@ -1807,79 +1837,94 @@
                 }
                 row_num += line_end - line_start;
             }
-            for (line_pos, (line, highlight_parts)) in
-                lines.by_ref().zip(highlights).take(MAX_SUGGESTION_HIGHLIGHT_LINES).enumerate()
-            {
-                // Print the span column to avoid confusion
-                buffer.puts(
-                    row_num,
-                    0,
-                    &self.maybe_anonymized(line_start + line_pos),
-                    Style::LineNumber,
-                );
-                if let DisplaySuggestion::Diff = show_code_change {
-                    // Add the line number for both addition and removal to drive the point home.
+            let mut unhighlighted_lines = Vec::new();
+            for (line_pos, (line, highlight_parts)) in lines.by_ref().zip(highlights).enumerate() {
+                debug!(%line_pos, %line, ?highlight_parts);
+
+                // Remember lines that are not highlighted to hide them if needed
+                if highlight_parts.is_empty() {
+                    unhighlighted_lines.push((line_pos, line));
+                    continue;
+                }
+
+                match unhighlighted_lines.len() {
+                    0 => (),
+                    // Since we show first line, "..." line and last line,
+                    // There is no reason to hide if there are 3 or less lines
+                    // (because then we just replace a line with ... which is
+                    // not helpful)
+                    n if n <= 3 => unhighlighted_lines.drain(..).for_each(|(p, l)| {
+                        self.draw_code_line(
+                            &mut buffer,
+                            &mut row_num,
+                            &Vec::new(),
+                            p,
+                            l,
+                            line_start,
+                            show_code_change,
+                            max_line_num_len,
+                            &file_lines,
+                            is_multiline,
+                        )
+                    }),
+                    // Print first unhighlighted line, "..." and last unhighlighted line, like so:
                     //
-                    // N - fn foo<A: T>(bar: A) {
-                    // N + fn foo(bar: impl T) {
-                    buffer.puts(
-                        row_num - 1,
-                        0,
-                        &self.maybe_anonymized(line_start + line_pos),
-                        Style::LineNumber,
-                    );
-                    buffer.puts(row_num - 1, max_line_num_len + 1, "- ", Style::Removal);
-                    buffer.puts(
-                        row_num - 1,
-                        max_line_num_len + 3,
-                        &normalize_whitespace(
-                            &*file_lines
-                                .file
-                                .get_line(file_lines.lines[line_pos].line_index)
-                                .unwrap(),
-                        ),
-                        Style::NoStyle,
-                    );
-                    buffer.puts(row_num, max_line_num_len + 1, "+ ", Style::Addition);
-                } else if is_multiline {
-                    match &highlight_parts[..] {
-                        [SubstitutionHighlight { start: 0, end }] if *end == line.len() => {
-                            buffer.puts(row_num, max_line_num_len + 1, "+ ", Style::Addition);
-                        }
-                        [] => {
-                            draw_col_separator(&mut buffer, row_num, max_line_num_len + 1);
-                        }
-                        _ => {
-                            buffer.puts(row_num, max_line_num_len + 1, "~ ", Style::Addition);
-                        }
+                    // LL | this line was highlighted
+                    // LL | this line is just for context
+                    //   ...
+                    // LL | this line is just for context
+                    // LL | this line was highlighted
+                    _ => {
+                        let last_line = unhighlighted_lines.pop();
+                        let first_line = unhighlighted_lines.drain(..).next();
+
+                        first_line.map(|(p, l)| {
+                            self.draw_code_line(
+                                &mut buffer,
+                                &mut row_num,
+                                &Vec::new(),
+                                p,
+                                l,
+                                line_start,
+                                show_code_change,
+                                max_line_num_len,
+                                &file_lines,
+                                is_multiline,
+                            )
+                        });
+
+                        buffer.puts(row_num, max_line_num_len - 1, "...", Style::LineNumber);
+                        row_num += 1;
+
+                        last_line.map(|(p, l)| {
+                            self.draw_code_line(
+                                &mut buffer,
+                                &mut row_num,
+                                &Vec::new(),
+                                p,
+                                l,
+                                line_start,
+                                show_code_change,
+                                max_line_num_len,
+                                &file_lines,
+                                is_multiline,
+                            )
+                        });
                     }
-                } else {
-                    draw_col_separator(&mut buffer, row_num, max_line_num_len + 1);
                 }
 
-                // print the suggestion
-                buffer.append(row_num, &normalize_whitespace(line), Style::NoStyle);
-
-                // Colorize addition/replacements with green.
-                for &SubstitutionHighlight { start, end } in highlight_parts {
-                    // Account for tabs when highlighting (#87972).
-                    let tabs: usize = line
-                        .chars()
-                        .take(start)
-                        .map(|ch| match ch {
-                            '\t' => 3,
-                            _ => 0,
-                        })
-                        .sum();
-                    buffer.set_style_range(
-                        row_num,
-                        max_line_num_len + 3 + start + tabs,
-                        max_line_num_len + 3 + end + tabs,
-                        Style::Addition,
-                        true,
-                    );
-                }
-                row_num += 1;
+                self.draw_code_line(
+                    &mut buffer,
+                    &mut row_num,
+                    highlight_parts,
+                    line_pos,
+                    line,
+                    line_start,
+                    show_code_change,
+                    max_line_num_len,
+                    &file_lines,
+                    is_multiline,
+                )
             }
 
             // This offset and the ones below need to be signed to account for replacement code
@@ -1888,7 +1933,7 @@
             // Only show an underline in the suggestions if the suggestion is not the
             // entirety of the code being shown and the displayed code is not multiline.
             if let DisplaySuggestion::Diff | DisplaySuggestion::Underline = show_code_change {
-                draw_col_separator(&mut buffer, row_num, max_line_num_len + 1);
+                draw_col_separator_no_space(&mut buffer, row_num, max_line_num_len + 1);
                 for part in parts {
                     let span_start_pos = sm.lookup_char_pos(part.span.lo()).col_display;
                     let span_end_pos = sm.lookup_char_pos(part.span.hi()).col_display;
@@ -2039,9 +2084,13 @@
                             ) {
                                 panic!("failed to emit error: {}", e);
                             }
-                        } else if let Err(e) =
-                            self.emit_suggestion_default(sugg, args, &Level::Help, max_line_num_len)
-                        {
+                        } else if let Err(e) = self.emit_suggestion_default(
+                            span,
+                            sugg,
+                            args,
+                            &Level::Help,
+                            max_line_num_len,
+                        ) {
                             panic!("failed to emit error: {}", e);
                         };
                     }
@@ -2060,6 +2109,90 @@
             }
         }
     }
+
+    fn draw_code_line(
+        &self,
+        buffer: &mut StyledBuffer,
+        row_num: &mut usize,
+        highlight_parts: &Vec<SubstitutionHighlight>,
+        line_pos: usize,
+        line: &str,
+        line_start: usize,
+        show_code_change: DisplaySuggestion,
+        max_line_num_len: usize,
+        file_lines: &FileLines,
+        is_multiline: bool,
+    ) {
+        // Print the span column to avoid confusion
+        buffer.puts(*row_num, 0, &self.maybe_anonymized(line_start + line_pos), Style::LineNumber);
+        if let DisplaySuggestion::Diff = show_code_change {
+            // Add the line number for both addition and removal to drive the point home.
+            //
+            // N - fn foo<A: T>(bar: A) {
+            // N + fn foo(bar: impl T) {
+            buffer.puts(
+                *row_num - 1,
+                0,
+                &self.maybe_anonymized(line_start + line_pos),
+                Style::LineNumber,
+            );
+            buffer.puts(*row_num - 1, max_line_num_len + 1, "- ", Style::Removal);
+            buffer.puts(
+                *row_num - 1,
+                max_line_num_len + 3,
+                &normalize_whitespace(
+                    &*file_lines.file.get_line(file_lines.lines[line_pos].line_index).unwrap(),
+                ),
+                Style::NoStyle,
+            );
+            buffer.puts(*row_num, max_line_num_len + 1, "+ ", Style::Addition);
+        } else if is_multiline {
+            match &highlight_parts[..] {
+                [SubstitutionHighlight { start: 0, end }] if *end == line.len() => {
+                    buffer.puts(*row_num, max_line_num_len + 1, "+ ", Style::Addition);
+                }
+                [] => {
+                    draw_col_separator(buffer, *row_num, max_line_num_len + 1);
+                }
+                _ => {
+                    buffer.puts(*row_num, max_line_num_len + 1, "~ ", Style::Addition);
+                }
+            }
+        } else {
+            draw_col_separator(buffer, *row_num, max_line_num_len + 1);
+        }
+
+        // print the suggestion
+        buffer.append(*row_num, &normalize_whitespace(line), Style::NoStyle);
+
+        // Colorize addition/replacements with green.
+        for &SubstitutionHighlight { start, end } in highlight_parts {
+            // Account for tabs when highlighting (#87972).
+            let tabs: usize = line
+                .chars()
+                .take(start)
+                .map(|ch| match ch {
+                    '\t' => 3,
+                    _ => 0,
+                })
+                .sum();
+            buffer.set_style_range(
+                *row_num,
+                max_line_num_len + 3 + start + tabs,
+                max_line_num_len + 3 + end + tabs,
+                Style::Addition,
+                true,
+            );
+        }
+        *row_num += 1;
+    }
+}
+
+#[derive(Clone, Copy)]
+enum DisplaySuggestion {
+    Underline,
+    Diff,
+    None,
 }
 
 impl FileWithAnnotatedLines {
diff --git a/compiler/rustc_errors/src/json.rs b/compiler/rustc_errors/src/json.rs
index 6ff5218..d4d1491 100644
--- a/compiler/rustc_errors/src/json.rs
+++ b/compiler/rustc_errors/src/json.rs
@@ -28,7 +28,7 @@
 use std::sync::{Arc, Mutex};
 use std::vec;
 
-use rustc_serialize::json::{as_json, as_pretty_json};
+use serde::Serialize;
 
 #[cfg(test)]
 mod tests;
@@ -126,9 +126,9 @@
     fn emit_diagnostic(&mut self, diag: &crate::Diagnostic) {
         let data = Diagnostic::from_errors_diagnostic(diag, self);
         let result = if self.pretty {
-            writeln!(&mut self.dst, "{}", as_pretty_json(&data))
+            writeln!(&mut self.dst, "{}", serde_json::to_string_pretty(&data).unwrap())
         } else {
-            writeln!(&mut self.dst, "{}", as_json(&data))
+            writeln!(&mut self.dst, "{}", serde_json::to_string(&data).unwrap())
         }
         .and_then(|_| self.dst.flush());
         if let Err(e) = result {
@@ -139,9 +139,9 @@
     fn emit_artifact_notification(&mut self, path: &Path, artifact_type: &str) {
         let data = ArtifactNotification { artifact: path, emit: artifact_type };
         let result = if self.pretty {
-            writeln!(&mut self.dst, "{}", as_pretty_json(&data))
+            writeln!(&mut self.dst, "{}", serde_json::to_string_pretty(&data).unwrap())
         } else {
-            writeln!(&mut self.dst, "{}", as_json(&data))
+            writeln!(&mut self.dst, "{}", serde_json::to_string(&data).unwrap())
         }
         .and_then(|_| self.dst.flush());
         if let Err(e) = result {
@@ -154,16 +154,16 @@
             .into_iter()
             .map(|mut diag| {
                 if diag.level == crate::Level::Allow {
-                    diag.level = crate::Level::Warning;
+                    diag.level = crate::Level::Warning(None);
                 }
                 FutureBreakageItem { diagnostic: Diagnostic::from_errors_diagnostic(&diag, self) }
             })
             .collect();
         let report = FutureIncompatReport { future_incompat_report: data };
         let result = if self.pretty {
-            writeln!(&mut self.dst, "{}", as_pretty_json(&report))
+            writeln!(&mut self.dst, "{}", serde_json::to_string_pretty(&report).unwrap())
         } else {
-            writeln!(&mut self.dst, "{}", as_json(&report))
+            writeln!(&mut self.dst, "{}", serde_json::to_string(&report).unwrap())
         }
         .and_then(|_| self.dst.flush());
         if let Err(e) = result {
@@ -175,9 +175,9 @@
         let lint_level = lint_level.as_str();
         let data = UnusedExterns { lint_level, unused_extern_names: unused_externs };
         let result = if self.pretty {
-            writeln!(&mut self.dst, "{}", as_pretty_json(&data))
+            writeln!(&mut self.dst, "{}", serde_json::to_string_pretty(&data).unwrap())
         } else {
-            writeln!(&mut self.dst, "{}", as_json(&data))
+            writeln!(&mut self.dst, "{}", serde_json::to_string(&data).unwrap())
         }
         .and_then(|_| self.dst.flush());
         if let Err(e) = result {
@@ -204,7 +204,7 @@
 
 // The following data types are provided just for serialisation.
 
-#[derive(Encodable)]
+#[derive(Serialize)]
 struct Diagnostic {
     /// The primary error message.
     message: String,
@@ -218,7 +218,7 @@
     rendered: Option<String>,
 }
 
-#[derive(Encodable)]
+#[derive(Serialize)]
 struct DiagnosticSpan {
     file_name: String,
     byte_start: u32,
@@ -245,7 +245,7 @@
     expansion: Option<Box<DiagnosticSpanMacroExpansion>>,
 }
 
-#[derive(Encodable)]
+#[derive(Serialize)]
 struct DiagnosticSpanLine {
     text: String,
 
@@ -255,7 +255,7 @@
     highlight_end: usize,
 }
 
-#[derive(Encodable)]
+#[derive(Serialize)]
 struct DiagnosticSpanMacroExpansion {
     /// span where macro was applied to generate this code; note that
     /// this may itself derive from a macro (if
@@ -269,7 +269,7 @@
     def_site_span: DiagnosticSpan,
 }
 
-#[derive(Encodable)]
+#[derive(Serialize)]
 struct DiagnosticCode {
     /// The code itself.
     code: String,
@@ -277,7 +277,7 @@
     explanation: Option<&'static str>,
 }
 
-#[derive(Encodable)]
+#[derive(Serialize)]
 struct ArtifactNotification<'a> {
     /// The path of the artifact.
     artifact: &'a Path,
@@ -285,12 +285,12 @@
     emit: &'a str,
 }
 
-#[derive(Encodable)]
+#[derive(Serialize)]
 struct FutureBreakageItem {
     diagnostic: Diagnostic,
 }
 
-#[derive(Encodable)]
+#[derive(Serialize)]
 struct FutureIncompatReport {
     future_incompat_report: Vec<FutureBreakageItem>,
 }
@@ -299,7 +299,7 @@
 // doctest component (as well as cargo).
 // We could unify this struct the one in rustdoc but they have different
 // ownership semantics, so doing so would create wasteful allocations.
-#[derive(Encodable)]
+#[derive(Serialize)]
 struct UnusedExterns<'a, 'b, 'c> {
     /// The severity level of the unused dependencies lint
     lint_level: &'a str,
diff --git a/compiler/rustc_errors/src/json/tests.rs b/compiler/rustc_errors/src/json/tests.rs
index 7eb6a49..d940d14 100644
--- a/compiler/rustc_errors/src/json/tests.rs
+++ b/compiler/rustc_errors/src/json/tests.rs
@@ -5,12 +5,18 @@
 
 use crate::emitter::{ColorConfig, HumanReadableErrorType};
 use crate::Handler;
-use rustc_serialize::json;
 use rustc_span::{BytePos, Span};
 
 use std::str;
 
-#[derive(Debug, PartialEq, Eq)]
+use serde::Deserialize;
+
+#[derive(Deserialize, Debug, PartialEq, Eq)]
+struct TestData {
+    spans: Vec<SpanTestData>,
+}
+
+#[derive(Deserialize, Debug, PartialEq, Eq)]
 struct SpanTestData {
     pub byte_start: u32,
     pub byte_end: u32,
@@ -61,19 +67,11 @@
 
         let bytes = output.lock().unwrap();
         let actual_output = str::from_utf8(&bytes).unwrap();
-        let actual_output = json::from_str(&actual_output).unwrap();
-        let spans = actual_output["spans"].as_array().unwrap();
+        let actual_output: TestData = serde_json::from_str(actual_output).unwrap();
+        let spans = actual_output.spans;
         assert_eq!(spans.len(), 1);
-        let obj = &spans[0];
-        let actual_output = SpanTestData {
-            byte_start: obj["byte_start"].as_u64().unwrap() as u32,
-            byte_end: obj["byte_end"].as_u64().unwrap() as u32,
-            line_start: obj["line_start"].as_u64().unwrap() as u32,
-            line_end: obj["line_end"].as_u64().unwrap() as u32,
-            column_start: obj["column_start"].as_u64().unwrap() as u32,
-            column_end: obj["column_end"].as_u64().unwrap() as u32,
-        };
-        assert_eq!(expected_output, actual_output);
+
+        assert_eq!(expected_output, spans[0])
     })
 }
 
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index 29643eaa..78b0892 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -3,14 +3,13 @@
 //! This module contains the code for creating and emitting diagnostics.
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
-#![feature(crate_visibility_modifier)]
 #![feature(drain_filter)]
 #![feature(backtrace)]
 #![feature(if_let_guard)]
 #![feature(let_else)]
 #![feature(never_type)]
-#![feature(nll)]
 #![feature(adt_const_params)]
+#![feature(rustc_attrs)]
 #![allow(incomplete_features)]
 #![allow(rustc::potential_query_instability)]
 
@@ -32,8 +31,9 @@
 use rustc_data_structures::sync::{self, Lock, Lrc};
 use rustc_data_structures::AtomicRef;
 pub use rustc_error_messages::{
-    fallback_fluent_bundle, fluent_bundle, DiagnosticMessage, FluentBundle, LanguageIdentifier,
-    LazyFallbackBundle, MultiSpan, SpanLabel, DEFAULT_LOCALE_RESOURCES,
+    fallback_fluent_bundle, fluent, fluent_bundle, DiagnosticMessage, FluentBundle,
+    LanguageIdentifier, LazyFallbackBundle, MultiSpan, SpanLabel, SubdiagnosticMessage,
+    DEFAULT_LOCALE_RESOURCES,
 };
 pub use rustc_lint_defs::{pluralize, Applicability};
 use rustc_span::source_map::SourceMap;
@@ -401,6 +401,9 @@
     emitter: Box<dyn Emitter + sync::Send>,
     delayed_span_bugs: Vec<Diagnostic>,
     delayed_good_path_bugs: Vec<DelayedDiagnostic>,
+    /// This flag indicates that an expected diagnostic was emitted and suppressed.
+    /// This is used for the `delayed_good_path_bugs` check.
+    suppressed_expected_diag: bool,
 
     /// This set contains the `DiagnosticId` of all emitted diagnostics to avoid
     /// emitting the same diagnostic with extended help (`--teach`) twice, which
@@ -496,7 +499,7 @@
         // instead of "require some error happened". Sadly that isn't ideal, as
         // lints can be `#[allow]`'d, potentially leading to this triggering.
         // Also, "good path" should be replaced with a better naming.
-        if !self.has_any_message() {
+        if !self.has_any_message() && !self.suppressed_expected_diag {
             let bugs = std::mem::replace(&mut self.delayed_good_path_bugs, Vec::new());
             self.flush_delayed(
                 bugs.into_iter().map(DelayedDiagnostic::decorate),
@@ -578,6 +581,7 @@
                 emitter,
                 delayed_span_bugs: Vec::new(),
                 delayed_good_path_bugs: Vec::new(),
+                suppressed_expected_diag: false,
                 taught_diagnostics: Default::default(),
                 emitted_diagnostic_codes: Default::default(),
                 emitted_diagnostics: Default::default(),
@@ -645,6 +649,7 @@
     /// Attempting to `.emit()` the builder will only emit if either:
     /// * `can_emit_warnings` is `true`
     /// * `is_force_warn` was set in `DiagnosticId::Lint`
+    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
     pub fn struct_span_warn(
         &self,
         span: impl Into<MultiSpan>,
@@ -655,7 +660,25 @@
         result
     }
 
+    /// Construct a builder at the `Warning` level at the given `span` and with the `msg`.
+    /// The `id` is used for lint emissions which should also fulfill a lint expectation.
+    ///
+    /// Attempting to `.emit()` the builder will only emit if either:
+    /// * `can_emit_warnings` is `true`
+    /// * `is_force_warn` was set in `DiagnosticId::Lint`
+    pub fn struct_span_warn_with_expectation(
+        &self,
+        span: impl Into<MultiSpan>,
+        msg: impl Into<DiagnosticMessage>,
+        id: LintExpectationId,
+    ) -> DiagnosticBuilder<'_, ()> {
+        let mut result = self.struct_warn_with_expectation(msg, id);
+        result.set_span(span);
+        result
+    }
+
     /// Construct a builder at the `Allow` level at the given `span` and with the `msg`.
+    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
     pub fn struct_span_allow(
         &self,
         span: impl Into<MultiSpan>,
@@ -668,6 +691,7 @@
 
     /// Construct a builder at the `Warning` level at the given `span` and with the `msg`.
     /// Also include a code.
+    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
     pub fn struct_span_warn_with_code(
         &self,
         span: impl Into<MultiSpan>,
@@ -684,16 +708,33 @@
     /// Attempting to `.emit()` the builder will only emit if either:
     /// * `can_emit_warnings` is `true`
     /// * `is_force_warn` was set in `DiagnosticId::Lint`
+    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
     pub fn struct_warn(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
-        DiagnosticBuilder::new(self, Level::Warning, msg)
+        DiagnosticBuilder::new(self, Level::Warning(None), msg)
+    }
+
+    /// Construct a builder at the `Warning` level with the `msg`. The `id` is used for
+    /// lint emissions which should also fulfill a lint expectation.
+    ///
+    /// Attempting to `.emit()` the builder will only emit if either:
+    /// * `can_emit_warnings` is `true`
+    /// * `is_force_warn` was set in `DiagnosticId::Lint`
+    pub fn struct_warn_with_expectation(
+        &self,
+        msg: impl Into<DiagnosticMessage>,
+        id: LintExpectationId,
+    ) -> DiagnosticBuilder<'_, ()> {
+        DiagnosticBuilder::new(self, Level::Warning(Some(id)), msg)
     }
 
     /// Construct a builder at the `Allow` level with the `msg`.
+    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
     pub fn struct_allow(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
         DiagnosticBuilder::new(self, Level::Allow, msg)
     }
 
     /// Construct a builder at the `Expect` level with the `msg`.
+    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
     pub fn struct_expect(
         &self,
         msg: impl Into<DiagnosticMessage>,
@@ -703,6 +744,7 @@
     }
 
     /// Construct a builder at the `Error` level at the given `span` and with the `msg`.
+    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
     pub fn struct_span_err(
         &self,
         span: impl Into<MultiSpan>,
@@ -714,6 +756,7 @@
     }
 
     /// Construct a builder at the `Error` level at the given `span`, with the `msg`, and `code`.
+    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
     pub fn struct_span_err_with_code(
         &self,
         span: impl Into<MultiSpan>,
@@ -727,6 +770,7 @@
 
     /// Construct a builder at the `Error` level with the `msg`.
     // FIXME: This method should be removed (every error should have an associated error code).
+    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
     pub fn struct_err(
         &self,
         msg: impl Into<DiagnosticMessage>,
@@ -741,6 +785,7 @@
     }
 
     /// Construct a builder at the `Error` level with the `msg` and the `code`.
+    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
     pub fn struct_err_with_code(
         &self,
         msg: impl Into<DiagnosticMessage>,
@@ -752,6 +797,7 @@
     }
 
     /// Construct a builder at the `Warn` level with the `msg` and the `code`.
+    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
     pub fn struct_warn_with_code(
         &self,
         msg: impl Into<DiagnosticMessage>,
@@ -763,6 +809,7 @@
     }
 
     /// Construct a builder at the `Fatal` level at the given `span` and with the `msg`.
+    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
     pub fn struct_span_fatal(
         &self,
         span: impl Into<MultiSpan>,
@@ -774,6 +821,7 @@
     }
 
     /// Construct a builder at the `Fatal` level at the given `span`, with the `msg`, and `code`.
+    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
     pub fn struct_span_fatal_with_code(
         &self,
         span: impl Into<MultiSpan>,
@@ -786,16 +834,19 @@
     }
 
     /// Construct a builder at the `Error` level with the `msg`.
+    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
     pub fn struct_fatal(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, !> {
         DiagnosticBuilder::new_fatal(self, msg)
     }
 
     /// Construct a builder at the `Help` level with the `msg`.
+    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
     pub fn struct_help(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
         DiagnosticBuilder::new(self, Level::Help, msg)
     }
 
     /// Construct a builder at the `Note` level with the `msg`.
+    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
     pub fn struct_note_without_error(
         &self,
         msg: impl Into<DiagnosticMessage>,
@@ -803,11 +854,13 @@
         DiagnosticBuilder::new(self, Level::Note, msg)
     }
 
+    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
     pub fn span_fatal(&self, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>) -> ! {
         self.emit_diag_at_span(Diagnostic::new(Fatal, msg), span);
         FatalError.raise()
     }
 
+    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
     pub fn span_fatal_with_code(
         &self,
         span: impl Into<MultiSpan>,
@@ -818,6 +871,7 @@
         FatalError.raise()
     }
 
+    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
     pub fn span_err(
         &self,
         span: impl Into<MultiSpan>,
@@ -826,6 +880,7 @@
         self.emit_diag_at_span(Diagnostic::new(Error { lint: false }, msg), span).unwrap()
     }
 
+    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
     pub fn span_err_with_code(
         &self,
         span: impl Into<MultiSpan>,
@@ -838,17 +893,19 @@
         );
     }
 
+    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
     pub fn span_warn(&self, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>) {
-        self.emit_diag_at_span(Diagnostic::new(Warning, msg), span);
+        self.emit_diag_at_span(Diagnostic::new(Warning(None), msg), span);
     }
 
+    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
     pub fn span_warn_with_code(
         &self,
         span: impl Into<MultiSpan>,
         msg: impl Into<DiagnosticMessage>,
         code: DiagnosticId,
     ) {
-        self.emit_diag_at_span(Diagnostic::new_with_code(Warning, Some(code), msg), span);
+        self.emit_diag_at_span(Diagnostic::new_with_code(Warning(None), Some(code), msg), span);
     }
 
     pub fn span_bug(&self, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>) -> ! {
@@ -902,7 +959,7 @@
     }
 
     pub fn warn(&self, msg: impl Into<DiagnosticMessage>) {
-        let mut db = DiagnosticBuilder::new(self, Warning, msg);
+        let mut db = DiagnosticBuilder::new(self, Warning(None), msg);
         db.emit();
     }
 
@@ -1001,20 +1058,17 @@
         let mut inner = self.inner.borrow_mut();
         let diags = std::mem::take(&mut inner.unstable_expect_diagnostics);
         inner.check_unstable_expect_diagnostics = true;
-        if diags.is_empty() {
-            return;
-        }
 
-        for mut diag in diags.into_iter() {
-            diag.update_unstable_expectation_id(unstable_to_stable);
+        if !diags.is_empty() {
+            inner.suppressed_expected_diag = true;
+            for mut diag in diags.into_iter() {
+                diag.update_unstable_expectation_id(unstable_to_stable);
 
-            let stable_id = diag
-                .level
-                .get_expectation_id()
-                .expect("all diagnostics inside `unstable_expect_diagnostics` must have a `LintExpectationId`");
-            inner.fulfilled_expectations.insert(stable_id);
-
-            (*TRACK_DIAGNOSTICS)(&diag);
+                // Here the diagnostic is given back to `emit_diagnostic` where it was first
+                // intercepted. Now it should be processed as usual, since the unstable expectation
+                // id is now stable.
+                inner.emit_diagnostic(&mut diag);
+            }
         }
 
         inner
@@ -1063,6 +1117,15 @@
 
     // FIXME(eddyb) this should ideally take `diagnostic` by value.
     fn emit_diagnostic(&mut self, diagnostic: &mut Diagnostic) -> Option<ErrorGuaranteed> {
+        // The `LintExpectationId` can be stable or unstable depending on when it was created.
+        // Diagnostics created before the definition of `HirId`s are unstable and can not yet
+        // be stored. Instead, they are buffered until the `LintExpectationId` is replaced by
+        // a stable one by the `LintLevelsBuilder`.
+        if let Some(LintExpectationId::Unstable { .. }) = diagnostic.level.get_expectation_id() {
+            self.unstable_expect_diagnostics.push(diagnostic.clone());
+            return None;
+        }
+
         if diagnostic.level == Level::DelayedBug {
             // FIXME(eddyb) this should check for `has_errors` and stop pushing
             // once *any* errors were emitted (and truncate `delayed_span_bugs`
@@ -1079,7 +1142,12 @@
             self.future_breakage_diagnostics.push(diagnostic.clone());
         }
 
-        if diagnostic.level == Warning
+        if let Some(expectation_id) = diagnostic.level.get_expectation_id() {
+            self.suppressed_expected_diag = true;
+            self.fulfilled_expectations.insert(expectation_id);
+        }
+
+        if matches!(diagnostic.level, Warning(_))
             && !self.flags.can_emit_warnings
             && !diagnostic.is_force_warn()
         {
@@ -1089,21 +1157,9 @@
             return None;
         }
 
-        // The `LintExpectationId` can be stable or unstable depending on when it was created.
-        // Diagnostics created before the definition of `HirId`s are unstable and can not yet
-        // be stored. Instead, they are buffered until the `LintExpectationId` is replaced by
-        // a stable one by the `LintLevelsBuilder`.
-        if let Level::Expect(LintExpectationId::Unstable { .. }) = diagnostic.level {
-            self.unstable_expect_diagnostics.push(diagnostic.clone());
-            return None;
-        }
-
         (*TRACK_DIAGNOSTICS)(diagnostic);
 
-        if let Level::Expect(expectation_id) = diagnostic.level {
-            self.fulfilled_expectations.insert(expectation_id);
-            return None;
-        } else if diagnostic.level == Allow {
+        if matches!(diagnostic.level, Level::Expect(_) | Level::Allow) {
             return None;
         }
 
@@ -1118,7 +1174,7 @@
             !this.emitted_diagnostics.insert(diagnostic_hash)
         };
 
-        // Only emit the diagnostic if we've been asked to deduplicate and
+        // Only emit the diagnostic if we've been asked to deduplicate or
         // haven't already emitted an equivalent diagnostic.
         if !(self.flags.deduplicate_diagnostics && already_emitted(self)) {
             debug!(?diagnostic);
@@ -1140,7 +1196,7 @@
             self.emitter.emit_diagnostic(&diagnostic);
             if diagnostic.is_error() {
                 self.deduplicated_err_count += 1;
-            } else if diagnostic.level == Warning {
+            } else if let Warning(_) = diagnostic.level {
                 self.deduplicated_warn_count += 1;
             }
         }
@@ -1193,7 +1249,7 @@
         match (errors.len(), warnings.len()) {
             (0, 0) => return,
             (0, _) => self.emitter.emit_diagnostic(&Diagnostic::new(
-                Level::Warning,
+                Level::Warning(None),
                 DiagnosticMessage::Str(warnings),
             )),
             (_, 0) => {
@@ -1426,7 +1482,10 @@
         /// If this error comes from a lint, don't abort compilation even when abort_if_errors() is called.
         lint: bool,
     },
-    Warning,
+    /// This [`LintExpectationId`] is used for expected lint diagnostics, which should
+    /// also emit a warning due to the `force-warn` flag. In all other cases this should
+    /// be `None`.
+    Warning(Option<LintExpectationId>),
     Note,
     /// A note that is only emitted once.
     OnceNote,
@@ -1449,7 +1508,7 @@
             Bug | DelayedBug | Fatal | Error { .. } => {
                 spec.set_fg(Some(Color::Red)).set_intense(true);
             }
-            Warning => {
+            Warning(_) => {
                 spec.set_fg(Some(Color::Yellow)).set_intense(cfg!(windows));
             }
             Note | OnceNote => {
@@ -1468,7 +1527,7 @@
         match self {
             Bug | DelayedBug => "error: internal compiler error",
             Fatal | Error { .. } => "error",
-            Warning => "warning",
+            Warning(_) => "warning",
             Note | OnceNote => "note",
             Help => "help",
             FailureNote => "failure-note",
@@ -1483,7 +1542,7 @@
 
     pub fn get_expectation_id(&self) -> Option<LintExpectationId> {
         match self {
-            Level::Expect(id) => Some(*id),
+            Level::Expect(id) | Level::Warning(Some(id)) => Some(*id),
             _ => None,
         }
     }
diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs
index 9ea09f7..245719b 100644
--- a/compiler/rustc_expand/src/base.rs
+++ b/compiler/rustc_expand/src/base.rs
@@ -4,7 +4,7 @@
 use rustc_ast::attr::MarkedAttrs;
 use rustc_ast::ptr::P;
 use rustc_ast::token::{self, Nonterminal};
-use rustc_ast::tokenstream::{CanSynthesizeMissingTokens, TokenStream};
+use rustc_ast::tokenstream::TokenStream;
 use rustc_ast::visit::{AssocCtxt, Visitor};
 use rustc_ast::{self as ast, Attribute, HasAttrs, Item, NodeId, PatKind};
 use rustc_attr::{self as attr, Deprecation, Stability};
@@ -13,8 +13,8 @@
 use rustc_errors::{Applicability, DiagnosticBuilder, ErrorGuaranteed, MultiSpan, PResult};
 use rustc_lint_defs::builtin::PROC_MACRO_BACK_COMPAT;
 use rustc_lint_defs::BuiltinLintDiagnostics;
-use rustc_parse::{self, parser, to_token_stream, MACRO_ARGUMENTS};
-use rustc_session::{parse::ParseSess, Limit, Session};
+use rustc_parse::{self, parser, MACRO_ARGUMENTS};
+use rustc_session::{parse::ParseSess, Limit, Session, SessionDiagnostic};
 use rustc_span::def_id::{CrateNum, DefId, LocalDefId};
 use rustc_span::edition::Edition;
 use rustc_span::hygiene::{AstPass, ExpnData, ExpnKind, LocalExpnId};
@@ -28,7 +28,7 @@
 use std::path::PathBuf;
 use std::rc::Rc;
 
-crate use rustc_span::hygiene::MacroKind;
+pub(crate) use rustc_span::hygiene::MacroKind;
 
 // When adding new variants, make sure to
 // adjust the `visit_*` / `flat_map_*` calls in `InvocationCollector`
@@ -109,20 +109,18 @@
         }
     }
 
-    pub fn to_tokens(&self, sess: &ParseSess) -> TokenStream {
+    pub fn to_tokens(&self) -> TokenStream {
         match self {
-            Annotatable::Item(node) => to_token_stream(node, sess, CanSynthesizeMissingTokens::No),
+            Annotatable::Item(node) => TokenStream::from_ast(node),
             Annotatable::TraitItem(node) | Annotatable::ImplItem(node) => {
-                to_token_stream(node, sess, CanSynthesizeMissingTokens::No)
+                TokenStream::from_ast(node)
             }
-            Annotatable::ForeignItem(node) => {
-                to_token_stream(node, sess, CanSynthesizeMissingTokens::No)
-            }
+            Annotatable::ForeignItem(node) => TokenStream::from_ast(node),
             Annotatable::Stmt(node) => {
                 assert!(!matches!(node.kind, ast::StmtKind::Empty));
-                to_token_stream(node, sess, CanSynthesizeMissingTokens::No)
+                TokenStream::from_ast(node)
             }
-            Annotatable::Expr(node) => to_token_stream(node, sess, CanSynthesizeMissingTokens::No),
+            Annotatable::Expr(node) => TokenStream::from_ast(node),
             Annotatable::Arm(..)
             | Annotatable::ExprField(..)
             | Annotatable::PatField(..)
@@ -268,7 +266,7 @@
     }
 }
 
-pub trait ProcMacro {
+pub trait BangProcMacro {
     fn expand<'cx>(
         &self,
         ecx: &'cx mut ExtCtxt<'_>,
@@ -277,7 +275,7 @@
     ) -> Result<TokenStream, ErrorGuaranteed>;
 }
 
-impl<F> ProcMacro for F
+impl<F> BangProcMacro for F
 where
     F: Fn(TokenStream) -> TokenStream,
 {
@@ -642,7 +640,7 @@
     /// A token-based function-like macro.
     Bang(
         /// An expander with signature TokenStream -> TokenStream.
-        Box<dyn ProcMacro + sync::Sync + sync::Send>,
+        Box<dyn BangProcMacro + sync::Sync + sync::Send>,
     ),
 
     /// An AST-based function-like macro.
@@ -1087,6 +1085,17 @@
         self.sess.parse_sess.span_diagnostic.struct_span_err(sp, msg)
     }
 
+    pub fn create_err(
+        &self,
+        err: impl SessionDiagnostic<'a>,
+    ) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
+        self.sess.create_err(err)
+    }
+
+    pub fn emit_err(&self, err: impl SessionDiagnostic<'a>) -> ErrorGuaranteed {
+        self.sess.emit_err(err)
+    }
+
     /// Emit `msg` attached to `sp`, without immediately stopping
     /// compilation.
     ///
@@ -1196,7 +1205,7 @@
                 err.span_suggestion(
                     expr.span.shrink_to_lo(),
                     "consider removing the leading `b`",
-                    String::new(),
+                    "",
                     Applicability::MaybeIncorrect,
                 );
                 Some((err, true))
diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs
index 301c67f..e73c31c 100644
--- a/compiler/rustc_expand/src/build.rs
+++ b/compiler/rustc_expand/src/build.rs
@@ -160,7 +160,7 @@
             attrs: AttrVec::new(),
             tokens: None,
         });
-        ast::Stmt { id: ast::DUMMY_NODE_ID, kind: ast::StmtKind::Local(local), span: sp }
+        self.stmt_local(local, sp)
     }
 
     // Generates `let _: Type;`, which is usually used for type assertions.
@@ -174,6 +174,10 @@
             attrs: AttrVec::new(),
             tokens: None,
         });
+        self.stmt_local(local, span)
+    }
+
+    pub fn stmt_local(&self, local: P<ast::Local>, span: Span) -> ast::Stmt {
         ast::Stmt { id: ast::DUMMY_NODE_ID, kind: ast::StmtKind::Local(local), span }
     }
 
@@ -514,7 +518,7 @@
         }
     }
 
-    // FIXME: unused `self`
+    // `self` is unused but keep it as method for the convenience use.
     pub fn fn_decl(&self, inputs: Vec<ast::Param>, output: ast::FnRetTy) -> P<ast::FnDecl> {
         P(ast::FnDecl { inputs, output })
     }
diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs
index 0b8cb07..3cada37 100644
--- a/compiler/rustc_expand/src/config.rs
+++ b/compiler/rustc_expand/src/config.rs
@@ -347,7 +347,7 @@
     /// Gives a compiler warning when the `cfg_attr` contains no attributes and
     /// is in the original source file. Gives a compiler error if the syntax of
     /// the attribute is incorrect.
-    crate fn expand_cfg_attr(&self, attr: Attribute, recursive: bool) -> Vec<Attribute> {
+    pub(crate) fn expand_cfg_attr(&self, attr: Attribute, recursive: bool) -> Vec<Attribute> {
         let Some((cfg_predicate, expanded_attrs)) =
             rustc_parse::parse_cfg_attr(&attr, &self.sess.parse_sess) else {
                 return vec![];
@@ -400,7 +400,7 @@
 
         // Use the `#` in `#[cfg_attr(pred, attr)]` as the `#` token
         // for `attr` when we expand it to `#[attr]`
-        let mut orig_trees = orig_tokens.trees();
+        let mut orig_trees = orig_tokens.into_trees();
         let TokenTree::Token(pound_token @ Token { kind: TokenKind::Pound, .. }) = orig_trees.next().unwrap() else {
             panic!("Bad tokens for attribute {:?}", attr);
         };
@@ -451,7 +451,7 @@
         attrs.iter().all(|attr| !is_cfg(attr) || self.cfg_true(attr))
     }
 
-    crate fn cfg_true(&self, attr: &Attribute) -> bool {
+    pub(crate) fn cfg_true(&self, attr: &Attribute) -> bool {
         let meta_item = match validate_attr::parse_meta(&self.sess.parse_sess, attr) {
             Ok(meta_item) => meta_item,
             Err(mut err) => {
@@ -465,7 +465,7 @@
     }
 
     /// If attributes are not allowed on expressions, emit an error for `attr`
-    crate fn maybe_emit_expr_attr_err(&self, attr: &Attribute) {
+    pub(crate) fn maybe_emit_expr_attr_err(&self, attr: &Attribute) {
         if !self.features.map_or(true, |features| features.stmt_expr_attributes) {
             let mut err = feature_err(
                 &self.sess.parse_sess,
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index a390e7a..978f87b 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -214,7 +214,7 @@
 }
 
 impl AstFragmentKind {
-    crate fn dummy(self, span: Span) -> AstFragment {
+    pub(crate) fn dummy(self, span: Span) -> AstFragment {
         self.make_from(DummyResult::any(span)).expect("couldn't create a dummy AST fragment")
     }
 
@@ -679,9 +679,12 @@
                                     )
                                 ) =>
                         {
-                            rustc_parse::fake_token_stream(&self.cx.sess.parse_sess, item_inner)
+                            rustc_parse::fake_token_stream_for_item(
+                                &self.cx.sess.parse_sess,
+                                item_inner,
+                            )
                         }
-                        _ => item.to_tokens(&self.cx.sess.parse_sess),
+                        _ => item.to_tokens(),
                     };
                     let attr_item = attr.unwrap_normal_item();
                     if let MacArgs::Eq(..) = attr_item.args {
@@ -942,7 +945,7 @@
                 err.span_suggestion(
                     semi_span,
                     "you might be missing a semicolon here",
-                    ";".to_owned(),
+                    ";",
                     Applicability::MaybeIncorrect,
                 );
             }
diff --git a/compiler/rustc_expand/src/lib.rs b/compiler/rustc_expand/src/lib.rs
index dc181ec..86ff110 100644
--- a/compiler/rustc_expand/src/lib.rs
+++ b/compiler/rustc_expand/src/lib.rs
@@ -1,7 +1,7 @@
 #![allow(rustc::potential_query_instability)]
+#![feature(array_windows)]
 #![feature(associated_type_bounds)]
 #![feature(associated_type_defaults)]
-#![feature(crate_visibility_modifier)]
 #![feature(if_let_guard)]
 #![feature(let_chains)]
 #![feature(let_else)]
@@ -21,7 +21,7 @@
 mod proc_macro_server;
 
 pub use mbe::macro_rules::compile_declarative_macro;
-crate use rustc_span::hygiene;
+pub(crate) use rustc_span::hygiene;
 pub mod base;
 pub mod build;
 #[macro_use]
@@ -30,7 +30,7 @@
 pub mod module;
 pub mod proc_macro;
 
-crate mod mbe;
+pub(crate) mod mbe;
 
 // HACK(Centril, #64197): These shouldn't really be here.
 // Rather, they should be with their respective modules which are defined in other crates.
diff --git a/compiler/rustc_expand/src/mbe.rs b/compiler/rustc_expand/src/mbe.rs
index 36295da..f42576b 100644
--- a/compiler/rustc_expand/src/mbe.rs
+++ b/compiler/rustc_expand/src/mbe.rs
@@ -3,12 +3,12 @@
 //! why we call this module `mbe`. For external documentation, prefer the
 //! official terminology: "declarative macros".
 
-crate mod macro_check;
-crate mod macro_parser;
-crate mod macro_rules;
-crate mod metavar_expr;
-crate mod quoted;
-crate mod transcribe;
+pub(crate) mod macro_check;
+pub(crate) mod macro_parser;
+pub(crate) mod macro_rules;
+pub(crate) mod metavar_expr;
+pub(crate) mod quoted;
+pub(crate) mod transcribe;
 
 use metavar_expr::MetaVarExpr;
 use rustc_ast::token::{Delimiter, NonterminalKind, Token, TokenKind};
diff --git a/compiler/rustc_expand/src/mbe/macro_parser.rs b/compiler/rustc_expand/src/mbe/macro_parser.rs
index ddfbef9..4fa91df 100644
--- a/compiler/rustc_expand/src/mbe/macro_parser.rs
+++ b/compiler/rustc_expand/src/mbe/macro_parser.rs
@@ -70,8 +70,8 @@
 //! eof: [a $( a )* a b ·]
 //! ```
 
-crate use NamedMatch::*;
-crate use ParseResult::*;
+pub(crate) use NamedMatch::*;
+pub(crate) use ParseResult::*;
 
 use crate::mbe::{KleeneOp, TokenTree};
 
@@ -262,7 +262,7 @@
 }
 
 /// Represents the possible results of an attempted parse.
-crate enum ParseResult<T> {
+pub(crate) enum ParseResult<T> {
     /// Parsed successfully.
     Success(T),
     /// Arm failed to match. If the second parameter is `token::Eof`, it indicates an unexpected
@@ -276,7 +276,7 @@
 /// A `ParseResult` where the `Success` variant contains a mapping of
 /// `MacroRulesNormalizedIdent`s to `NamedMatch`es. This represents the mapping
 /// of metavars to the token trees they bind to.
-crate type NamedParseResult = ParseResult<FxHashMap<MacroRulesNormalizedIdent, NamedMatch>>;
+pub(crate) type NamedParseResult = ParseResult<FxHashMap<MacroRulesNormalizedIdent, NamedMatch>>;
 
 /// Count how many metavars declarations are in `matcher`.
 pub(super) fn count_metavar_decls(matcher: &[TokenTree]) -> usize {
@@ -340,7 +340,7 @@
 /// ])
 /// ```
 #[derive(Debug, Clone)]
-crate enum NamedMatch {
+pub(crate) enum NamedMatch {
     MatchedSeq(Vec<NamedMatch>),
 
     // A metavar match of type `tt`.
@@ -362,7 +362,7 @@
 }
 
 // Note: the vectors could be created and dropped within `parse_tt`, but to avoid excess
-// allocations we have a single vector fo each kind that is cleared and reused repeatedly.
+// allocations we have a single vector for each kind that is cleared and reused repeatedly.
 pub struct TtParser {
     macro_name: Ident,
 
diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs
index 4cc3169..f40c365 100644
--- a/compiler/rustc_expand/src/mbe/macro_rules.rs
+++ b/compiler/rustc_expand/src/mbe/macro_rules.rs
@@ -33,7 +33,7 @@
 use std::{mem, slice};
 use tracing::debug;
 
-crate struct ParserAnyMacro<'a> {
+pub(crate) struct ParserAnyMacro<'a> {
     parser: Parser<'a>,
 
     /// Span of the expansion site of the macro this parser is for
@@ -47,7 +47,7 @@
     is_local: bool,
 }
 
-crate fn annotate_err_with_kind(err: &mut Diagnostic, kind: AstFragmentKind, span: Span) {
+pub(crate) fn annotate_err_with_kind(err: &mut Diagnostic, kind: AstFragmentKind, span: Span) {
     match kind {
         AstFragmentKind::Ty => {
             err.span_label(span, "this macro call doesn't expand to a type");
@@ -102,7 +102,7 @@
                 e.span_suggestion_verbose(
                     site_span.shrink_to_hi(),
                     "add `;` to interpret the expansion as a statement",
-                    ";".to_string(),
+                    ";",
                     Applicability::MaybeIncorrect,
                 );
             }
@@ -113,7 +113,7 @@
 }
 
 impl<'a> ParserAnyMacro<'a> {
-    crate fn make(mut self: Box<ParserAnyMacro<'a>>, kind: AstFragmentKind) -> AstFragment {
+    pub(crate) fn make(mut self: Box<ParserAnyMacro<'a>>, kind: AstFragmentKind) -> AstFragment {
         let ParserAnyMacro {
             site_span,
             macro_ident,
@@ -123,7 +123,7 @@
             is_trailing_mac,
             is_local,
         } = *self;
-        let snapshot = &mut parser.clone();
+        let snapshot = &mut parser.create_snapshot_for_diagnostic();
         let fragment = match parse_ast_fragment(parser, kind) {
             Ok(f) => f,
             Err(err) => {
@@ -204,7 +204,7 @@
 
 /// Expands the rules based macro defined by `lhses` and `rhses` for a given
 /// input `arg`.
-fn expand_macro<'cx, 'tt>(
+fn expand_macro<'cx>(
     cx: &'cx mut ExtCtxt<'_>,
     sp: Span,
     def_span: Span,
@@ -212,8 +212,8 @@
     name: Ident,
     transparency: Transparency,
     arg: TokenStream,
-    lhses: &'tt [Vec<MatcherLoc>],
-    rhses: &'tt [mbe::TokenTree],
+    lhses: &[Vec<MatcherLoc>],
+    rhses: &[mbe::TokenTree],
 ) -> Box<dyn MacResult + 'cx> {
     let sess = &cx.sess.parse_sess;
     // Macros defined in the current crate have a real node id,
@@ -357,7 +357,7 @@
                     err.span_suggestion_short(
                         comma_span,
                         "missing comma here",
-                        ", ".to_string(),
+                        ", ",
                         Applicability::MachineApplicable,
                     );
                 }
@@ -380,7 +380,7 @@
     features: &Features,
     def: &ast::Item,
     edition: Edition,
-) -> (SyntaxExtension, Vec<Span>) {
+) -> (SyntaxExtension, Vec<(usize, Span)>) {
     debug!("compile_declarative_macro: {:?}", def);
     let mk_syn_ext = |expander| {
         SyntaxExtension::new(
@@ -539,11 +539,22 @@
         None => {}
     }
 
-    // Compute the spans of the macro rules
-    // We only take the span of the lhs here,
-    // so that the spans of created warnings are smaller.
-    let rule_spans = if def.id != DUMMY_NODE_ID {
-        lhses.iter().map(|lhs| lhs.span()).collect::<Vec<_>>()
+    // Compute the spans of the macro rules for unused rule linting.
+    // To avoid warning noise, only consider the rules of this
+    // macro for the lint, if all rules are valid.
+    // Also, we are only interested in non-foreign macros.
+    let rule_spans = if valid && def.id != DUMMY_NODE_ID {
+        lhses
+            .iter()
+            .zip(rhses.iter())
+            .enumerate()
+            // If the rhs contains an invocation like compile_error!,
+            // don't consider the rule for the unused rule lint.
+            .filter(|(_idx, (_lhs, rhs))| !has_compile_error_macro(rhs))
+            // We only take the span of the lhs here,
+            // so that the spans of created warnings are smaller.
+            .map(|(idx, (lhs, _rhs))| (idx, lhs.span()))
+            .collect::<Vec<_>>()
     } else {
         Vec::new()
     };
@@ -651,6 +662,29 @@
     err == sess.span_diagnostic.err_count()
 }
 
+fn has_compile_error_macro(rhs: &mbe::TokenTree) -> bool {
+    match rhs {
+        mbe::TokenTree::Delimited(_sp, d) => {
+            let has_compile_error = d.tts.array_windows::<3>().any(|[ident, bang, args]| {
+                if let mbe::TokenTree::Token(ident) = ident &&
+                        let TokenKind::Ident(ident, _) = ident.kind &&
+                        ident == sym::compile_error &&
+                        let mbe::TokenTree::Token(bang) = bang &&
+                        let TokenKind::Not = bang.kind &&
+                        let mbe::TokenTree::Delimited(_, del) = args &&
+                        del.delim != Delimiter::Invisible
+                    {
+                        true
+                    } else {
+                        false
+                    }
+            });
+            if has_compile_error { true } else { d.tts.iter().any(has_compile_error_macro) }
+        }
+        _ => false,
+    }
+}
+
 // `The FirstSets` for a matcher is a mapping from subsequences in the
 // matcher to the FIRST set for that subsequence.
 //
diff --git a/compiler/rustc_expand/src/mbe/metavar_expr.rs b/compiler/rustc_expand/src/mbe/metavar_expr.rs
index cdc5e20..45c462b 100644
--- a/compiler/rustc_expand/src/mbe/metavar_expr.rs
+++ b/compiler/rustc_expand/src/mbe/metavar_expr.rs
@@ -1,5 +1,5 @@
 use rustc_ast::token::{self, Delimiter};
-use rustc_ast::tokenstream::{Cursor, TokenStream, TokenTree};
+use rustc_ast::tokenstream::{CursorRef, TokenStream, TokenTree};
 use rustc_ast::{LitIntType, LitKind};
 use rustc_ast_pretty::pprust;
 use rustc_errors::{Applicability, PResult};
@@ -9,7 +9,7 @@
 
 /// A meta-variable expression, for expansions based on properties of meta-variables.
 #[derive(Debug, Clone, PartialEq, Encodable, Decodable)]
-crate enum MetaVarExpr {
+pub(crate) enum MetaVarExpr {
     /// The number of repetitions of an identifier, optionally limited to a number
     /// of outer-most repetition depths. If the depth limit is `None` then the depth is unlimited.
     Count(Ident, Option<usize>),
@@ -28,7 +28,7 @@
 
 impl MetaVarExpr {
     /// Attempt to parse a meta-variable expression from a token stream.
-    crate fn parse<'sess>(
+    pub(crate) fn parse<'sess>(
         input: &TokenStream,
         outer_span: Span,
         sess: &'sess ParseSess,
@@ -52,7 +52,7 @@
                 err.span_suggestion(
                     ident.span,
                     "supported expressions are count, ignore, index and length",
-                    String::new(),
+                    "",
                     Applicability::MachineApplicable,
                 );
                 return Err(err);
@@ -62,7 +62,7 @@
         Ok(rslt)
     }
 
-    crate fn ident(&self) -> Option<Ident> {
+    pub(crate) fn ident(&self) -> Option<Ident> {
         match *self {
             MetaVarExpr::Count(ident, _) | MetaVarExpr::Ignore(ident) => Some(ident),
             MetaVarExpr::Index(..) | MetaVarExpr::Length(..) => None,
@@ -71,12 +71,14 @@
 }
 
 // Checks if there are any remaining tokens. For example, `${ignore(ident ... a b c ...)}`
-fn check_trailing_token<'sess>(iter: &mut Cursor, sess: &'sess ParseSess) -> PResult<'sess, ()> {
+fn check_trailing_token<'sess>(
+    iter: &mut CursorRef<'_>,
+    sess: &'sess ParseSess,
+) -> PResult<'sess, ()> {
     if let Some(tt) = iter.next() {
-        let mut diag = sess.span_diagnostic.struct_span_err(
-            tt.span(),
-            &format!("unexpected token: {}", pprust::tt_to_string(&tt)),
-        );
+        let mut diag = sess
+            .span_diagnostic
+            .struct_span_err(tt.span(), &format!("unexpected token: {}", pprust::tt_to_string(tt)));
         diag.span_note(tt.span(), "meta-variable expression must not have trailing tokens");
         Err(diag)
     } else {
@@ -86,7 +88,7 @@
 
 /// Parse a meta-variable `count` expression: `count(ident[, depth])`
 fn parse_count<'sess>(
-    iter: &mut Cursor,
+    iter: &mut CursorRef<'_>,
     sess: &'sess ParseSess,
     span: Span,
 ) -> PResult<'sess, MetaVarExpr> {
@@ -97,7 +99,7 @@
 
 /// Parses the depth used by index(depth) and length(depth).
 fn parse_depth<'sess>(
-    iter: &mut Cursor,
+    iter: &mut CursorRef<'_>,
     sess: &'sess ParseSess,
     span: Span,
 ) -> PResult<'sess, usize> {
@@ -110,7 +112,7 @@
             "meta-variable expression depth must be a literal"
         ));
     };
-    if let Ok(lit_kind) = LitKind::from_lit_token(lit)
+    if let Ok(lit_kind) = LitKind::from_lit_token(*lit)
         && let LitKind::Int(n_u128, LitIntType::Unsuffixed) = lit_kind
         && let Ok(n_usize) = usize::try_from(n_u128)
     {
@@ -124,7 +126,7 @@
 
 /// Parses an generic ident
 fn parse_ident<'sess>(
-    iter: &mut Cursor,
+    iter: &mut CursorRef<'_>,
     sess: &'sess ParseSess,
     span: Span,
 ) -> PResult<'sess, Ident> {
@@ -132,7 +134,7 @@
         if let Some((elem, false)) = token.ident() {
             return Ok(elem);
         }
-        let token_str = pprust::token_to_string(&token);
+        let token_str = pprust::token_to_string(token);
         let mut err = sess.span_diagnostic.struct_span_err(
             span,
             &format!("expected identifier, found `{}`", &token_str)
@@ -140,7 +142,7 @@
         err.span_suggestion(
             token.span,
             &format!("try removing `{}`", &token_str),
-            String::new(),
+            "",
             Applicability::MaybeIncorrect,
         );
         return Err(err);
@@ -150,7 +152,7 @@
 
 /// Tries to move the iterator forward returning `true` if there is a comma. If not, then the
 /// iterator is not modified and the result is `false`.
-fn try_eat_comma(iter: &mut Cursor) -> bool {
+fn try_eat_comma(iter: &mut CursorRef<'_>) -> bool {
     if let Some(TokenTree::Token(token::Token { kind: token::Comma, .. })) = iter.look_ahead(0) {
         let _ = iter.next();
         return true;
diff --git a/compiler/rustc_expand/src/mbe/quoted.rs b/compiler/rustc_expand/src/mbe/quoted.rs
index d52de24..707cb73 100644
--- a/compiler/rustc_expand/src/mbe/quoted.rs
+++ b/compiler/rustc_expand/src/mbe/quoted.rs
@@ -48,7 +48,7 @@
 
     // For each token tree in `input`, parse the token into a `self::TokenTree`, consuming
     // additional trees if need be.
-    let mut trees = input.trees();
+    let mut trees = input.into_trees();
     while let Some(tree) = trees.next() {
         // Given the parsed tree, if there is a metavar and we are expecting matchers, actually
         // parse out the matcher (i.e., in `$id:ident` this would parse the `:` and `ident`).
diff --git a/compiler/rustc_expand/src/module.rs b/compiler/rustc_expand/src/module.rs
index 2a059f3..876faad3 100644
--- a/compiler/rustc_expand/src/module.rs
+++ b/compiler/rustc_expand/src/module.rs
@@ -26,7 +26,7 @@
     pub dir_ownership: DirOwnership,
 }
 
-crate struct ParsedExternalMod {
+pub(crate) struct ParsedExternalMod {
     pub items: Vec<P<Item>>,
     pub spans: ModSpans,
     pub file_path: PathBuf,
@@ -42,7 +42,7 @@
     ParserError(DiagnosticBuilder<'a, ErrorGuaranteed>),
 }
 
-crate fn parse_external_mod(
+pub(crate) fn parse_external_mod(
     sess: &Session,
     ident: Ident,
     span: Span, // The span to blame on errors.
@@ -78,7 +78,7 @@
     ParsedExternalMod { items, spans, file_path, dir_path, dir_ownership }
 }
 
-crate fn mod_dir_path(
+pub(crate) fn mod_dir_path(
     sess: &Session,
     ident: Ident,
     attrs: &[Attribute],
diff --git a/compiler/rustc_expand/src/parse/tests.rs b/compiler/rustc_expand/src/parse/tests.rs
index 5d447d9..8da7879 100644
--- a/compiler/rustc_expand/src/parse/tests.rs
+++ b/compiler/rustc_expand/src/parse/tests.rs
@@ -61,7 +61,7 @@
 fn string_to_tts_macro() {
     create_default_session_globals_then(|| {
         let tts: Vec<_> =
-            string_to_stream("macro_rules! zip (($a)=>($a))".to_string()).trees().collect();
+            string_to_stream("macro_rules! zip (($a)=>($a))".to_string()).into_trees().collect();
         let tts: &[TokenTree] = &tts[..];
 
         match tts {
@@ -293,7 +293,7 @@
         .unwrap();
 
         let tts: Vec<_> = match expr.kind {
-            ast::ExprKind::MacCall(ref mac) => mac.args.inner_tokens().trees().collect(),
+            ast::ExprKind::MacCall(ref mac) => mac.args.inner_tokens().into_trees().collect(),
             _ => panic!("not a macro"),
         };
 
diff --git a/compiler/rustc_expand/src/proc_macro.rs b/compiler/rustc_expand/src/proc_macro.rs
index 6c74d46..9e1cd29 100644
--- a/compiler/rustc_expand/src/proc_macro.rs
+++ b/compiler/rustc_expand/src/proc_macro.rs
@@ -14,10 +14,10 @@
 const EXEC_STRATEGY: pm::bridge::server::SameThread = pm::bridge::server::SameThread;
 
 pub struct BangProcMacro {
-    pub client: pm::bridge::client::Client<fn(pm::TokenStream) -> pm::TokenStream>,
+    pub client: pm::bridge::client::Client<pm::TokenStream, pm::TokenStream>,
 }
 
-impl base::ProcMacro for BangProcMacro {
+impl base::BangProcMacro for BangProcMacro {
     fn expand<'cx>(
         &self,
         ecx: &'cx mut ExtCtxt<'_>,
@@ -42,7 +42,7 @@
 }
 
 pub struct AttrProcMacro {
-    pub client: pm::bridge::client::Client<fn(pm::TokenStream, pm::TokenStream) -> pm::TokenStream>,
+    pub client: pm::bridge::client::Client<(pm::TokenStream, pm::TokenStream), pm::TokenStream>,
 }
 
 impl base::AttrProcMacro for AttrProcMacro {
@@ -72,11 +72,11 @@
     }
 }
 
-pub struct ProcMacroDerive {
-    pub client: pm::bridge::client::Client<fn(pm::TokenStream) -> pm::TokenStream>,
+pub struct DeriveProcMacro {
+    pub client: pm::bridge::client::Client<pm::TokenStream, pm::TokenStream>,
 }
 
-impl MultiItemModifier for ProcMacroDerive {
+impl MultiItemModifier for DeriveProcMacro {
     fn expand(
         &self,
         ecx: &mut ExtCtxt<'_>,
@@ -96,7 +96,7 @@
             };
             TokenTree::token(token::Interpolated(Lrc::new(nt)), DUMMY_SP).into()
         } else {
-            item.to_tokens(&ecx.sess.parse_sess)
+            item.to_tokens()
         };
 
         let stream = {
diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs
index c0c786e..1e4193a 100644
--- a/compiler/rustc_expand/src/proc_macro_server.rs
+++ b/compiler/rustc_expand/src/proc_macro_server.rs
@@ -2,14 +2,13 @@
 
 use rustc_ast as ast;
 use rustc_ast::token;
-use rustc_ast::tokenstream::{self, CanSynthesizeMissingTokens};
-use rustc_ast::tokenstream::{DelimSpan, Spacing::*, TokenStream, TreeAndSpacing};
+use rustc_ast::tokenstream::{self, DelimSpan, Spacing::*, TokenStream, TreeAndSpacing};
 use rustc_ast_pretty::pprust;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::{Diagnostic, MultiSpan, PResult};
 use rustc_parse::lexer::nfc_normalize;
-use rustc_parse::{nt_to_tokenstream, parse_stream_from_source_str};
+use rustc_parse::parse_stream_from_source_str;
 use rustc_session::parse::ParseSess;
 use rustc_span::def_id::CrateNum;
 use rustc_span::symbol::{self, kw, sym, Symbol};
@@ -179,10 +178,9 @@
                 TokenTree::Ident(Ident::new(rustc.sess(), ident.name, is_raw, ident.span))
             }
             Interpolated(nt) => {
-                let stream = nt_to_tokenstream(&nt, rustc.sess(), CanSynthesizeMissingTokens::No);
                 TokenTree::Group(Group {
                     delimiter: pm::Delimiter::None,
-                    stream,
+                    stream: TokenStream::from_nonterminal_ast(&nt),
                     span: DelimSpan::from_single(span),
                     flatten: crate::base::nt_pretty_printing_compatibility_hack(&nt, rustc.sess()),
                 })
@@ -269,7 +267,7 @@
     fn to_internal(self) -> rustc_errors::Level {
         match self {
             Level::Error => rustc_errors::Level::Error { lint: false },
-            Level::Warning => rustc_errors::Level::Warning,
+            Level::Warning => rustc_errors::Level::Warning(None),
             Level::Note => rustc_errors::Level::Note,
             Level::Help => rustc_errors::Level::Help,
             _ => unreachable!("unknown proc_macro::Level variant: {:?}", self),
@@ -280,12 +278,6 @@
 pub struct FreeFunctions;
 
 #[derive(Clone)]
-pub struct TokenStreamIter {
-    cursor: tokenstream::Cursor,
-    stack: Vec<TokenTree<Group, Punct, Ident, Literal>>,
-}
-
-#[derive(Clone)]
 pub struct Group {
     delimiter: Delimiter,
     stream: TokenStream,
@@ -337,6 +329,7 @@
         sess.symbol_gallery.insert(sym, span);
         Ident { sym, is_raw, span }
     }
+
     fn dollar_crate(span: Span) -> Ident {
         // `$crate` is accepted as an ident only if it comes from the compiler.
         Ident { sym: kw::DollarCrate, is_raw: false, span }
@@ -384,8 +377,6 @@
 impl server::Types for Rustc<'_, '_> {
     type FreeFunctions = FreeFunctions;
     type TokenStream = TokenStream;
-    type TokenStreamBuilder = tokenstream::TokenStreamBuilder;
-    type TokenStreamIter = TokenStreamIter;
     type Group = Group;
     type Punct = Punct;
     type Ident = Ident;
@@ -410,12 +401,10 @@
 }
 
 impl server::TokenStream for Rustc<'_, '_> {
-    fn new(&mut self) -> Self::TokenStream {
-        TokenStream::default()
-    }
     fn is_empty(&mut self, stream: &Self::TokenStream) -> bool {
         stream.is_empty()
     }
+
     fn from_str(&mut self, src: &str) -> Self::TokenStream {
         parse_stream_from_source_str(
             FileName::proc_macro_source_code(src),
@@ -424,9 +413,11 @@
             Some(self.call_site),
         )
     }
+
     fn to_string(&mut self, stream: &Self::TokenStream) -> String {
         pprust::tts_to_string(stream)
     }
+
     fn expand_expr(&mut self, stream: &Self::TokenStream) -> Result<Self::TokenStream, ()> {
         // Parse the expression from our tokenstream.
         let expr: PResult<'_, _> = try {
@@ -454,7 +445,7 @@
 
         // NOTE: For now, limit `expand_expr` to exclusively expand to literals.
         // This may be relaxed in the future.
-        // We don't use `nt_to_tokenstream` as the tokenstream currently cannot
+        // We don't use `TokenStream::from_ast` as the tokenstream currently cannot
         // be recovered in the general case.
         match &expr.kind {
             ast::ExprKind::Lit(l) => {
@@ -477,78 +468,110 @@
             _ => Err(()),
         }
     }
+
     fn from_token_tree(
         &mut self,
         tree: TokenTree<Self::Group, Self::Punct, Self::Ident, Self::Literal>,
     ) -> Self::TokenStream {
         tree.to_internal()
     }
-    fn into_iter(&mut self, stream: Self::TokenStream) -> Self::TokenStreamIter {
-        TokenStreamIter { cursor: stream.trees(), stack: vec![] }
-    }
-}
 
-impl server::TokenStreamBuilder for Rustc<'_, '_> {
-    fn new(&mut self) -> Self::TokenStreamBuilder {
-        tokenstream::TokenStreamBuilder::new()
-    }
-    fn push(&mut self, builder: &mut Self::TokenStreamBuilder, stream: Self::TokenStream) {
-        builder.push(stream);
-    }
-    fn build(&mut self, builder: Self::TokenStreamBuilder) -> Self::TokenStream {
+    fn concat_trees(
+        &mut self,
+        base: Option<Self::TokenStream>,
+        trees: Vec<TokenTree<Self::Group, Self::Punct, Self::Ident, Self::Literal>>,
+    ) -> Self::TokenStream {
+        let mut builder = tokenstream::TokenStreamBuilder::new();
+        if let Some(base) = base {
+            builder.push(base);
+        }
+        for tree in trees {
+            builder.push(tree.to_internal());
+        }
         builder.build()
     }
-}
 
-impl server::TokenStreamIter for Rustc<'_, '_> {
-    fn next(
+    fn concat_streams(
         &mut self,
-        iter: &mut Self::TokenStreamIter,
-    ) -> Option<TokenTree<Self::Group, Self::Punct, Self::Ident, Self::Literal>> {
+        base: Option<Self::TokenStream>,
+        streams: Vec<Self::TokenStream>,
+    ) -> Self::TokenStream {
+        let mut builder = tokenstream::TokenStreamBuilder::new();
+        if let Some(base) = base {
+            builder.push(base);
+        }
+        for stream in streams {
+            builder.push(stream);
+        }
+        builder.build()
+    }
+
+    fn into_trees(
+        &mut self,
+        stream: Self::TokenStream,
+    ) -> Vec<TokenTree<Self::Group, Self::Punct, Self::Ident, Self::Literal>> {
+        // FIXME: This is a raw port of the previous approach (which had a
+        // `TokenStreamIter` server-side object with a single `next` method),
+        // and can probably be optimized (for bulk conversion).
+        let mut cursor = stream.into_trees();
+        let mut stack = Vec::new();
+        let mut tts = Vec::new();
         loop {
-            let tree = iter.stack.pop().or_else(|| {
-                let next = iter.cursor.next_with_spacing()?;
-                Some(TokenTree::from_internal((next, &mut iter.stack, self)))
-            })?;
-            // A hack used to pass AST fragments to attribute and derive macros
-            // as a single nonterminal token instead of a token stream.
-            // Such token needs to be "unwrapped" and not represented as a delimited group.
-            // FIXME: It needs to be removed, but there are some compatibility issues (see #73345).
-            if let TokenTree::Group(ref group) = tree {
-                if group.flatten {
-                    iter.cursor.append(group.stream.clone());
-                    continue;
+            let next = stack.pop().or_else(|| {
+                let next = cursor.next_with_spacing()?;
+                Some(TokenTree::from_internal((next, &mut stack, self)))
+            });
+            match next {
+                Some(TokenTree::Group(group)) => {
+                    // A hack used to pass AST fragments to attribute and derive
+                    // macros as a single nonterminal token instead of a token
+                    // stream.  Such token needs to be "unwrapped" and not
+                    // represented as a delimited group.
+                    // FIXME: It needs to be removed, but there are some
+                    // compatibility issues (see #73345).
+                    if group.flatten {
+                        tts.append(&mut self.into_trees(group.stream));
+                    } else {
+                        tts.push(TokenTree::Group(group));
+                    }
                 }
+                Some(tt) => tts.push(tt),
+                None => return tts,
             }
-            return Some(tree);
         }
     }
 }
 
 impl server::Group for Rustc<'_, '_> {
-    fn new(&mut self, delimiter: Delimiter, stream: Self::TokenStream) -> Self::Group {
+    fn new(&mut self, delimiter: Delimiter, stream: Option<Self::TokenStream>) -> Self::Group {
         Group {
             delimiter,
-            stream,
+            stream: stream.unwrap_or_default(),
             span: DelimSpan::from_single(server::Span::call_site(self)),
             flatten: false,
         }
     }
+
     fn delimiter(&mut self, group: &Self::Group) -> Delimiter {
         group.delimiter
     }
+
     fn stream(&mut self, group: &Self::Group) -> Self::TokenStream {
         group.stream.clone()
     }
+
     fn span(&mut self, group: &Self::Group) -> Self::Span {
         group.span.entire()
     }
+
     fn span_open(&mut self, group: &Self::Group) -> Self::Span {
         group.span.open
     }
+
     fn span_close(&mut self, group: &Self::Group) -> Self::Span {
         group.span.close
     }
+
     fn set_span(&mut self, group: &mut Self::Group, span: Self::Span) {
         group.span = DelimSpan::from_single(span);
     }
@@ -558,15 +581,19 @@
     fn new(&mut self, ch: char, spacing: Spacing) -> Self::Punct {
         Punct::new(ch, spacing == Spacing::Joint, server::Span::call_site(self))
     }
+
     fn as_char(&mut self, punct: Self::Punct) -> char {
         punct.ch
     }
+
     fn spacing(&mut self, punct: Self::Punct) -> Spacing {
         if punct.joint { Spacing::Joint } else { Spacing::Alone }
     }
+
     fn span(&mut self, punct: Self::Punct) -> Self::Span {
         punct.span
     }
+
     fn with_span(&mut self, punct: Self::Punct, span: Self::Span) -> Self::Punct {
         Punct { span, ..punct }
     }
@@ -576,9 +603,11 @@
     fn new(&mut self, string: &str, span: Self::Span, is_raw: bool) -> Self::Ident {
         Ident::new(self.sess(), Symbol::intern(string), is_raw, span)
     }
+
     fn span(&mut self, ident: Self::Ident) -> Self::Span {
         ident.span
     }
+
     fn with_span(&mut self, ident: Self::Ident, span: Self::Span) -> Self::Ident {
         Ident { span, ..ident }
     }
@@ -630,45 +659,57 @@
 
         Ok(Literal { lit, span: self.call_site })
     }
+
     fn to_string(&mut self, literal: &Self::Literal) -> String {
         literal.lit.to_string()
     }
+
     fn debug_kind(&mut self, literal: &Self::Literal) -> String {
         format!("{:?}", literal.lit.kind)
     }
+
     fn symbol(&mut self, literal: &Self::Literal) -> String {
         literal.lit.symbol.to_string()
     }
+
     fn suffix(&mut self, literal: &Self::Literal) -> Option<String> {
         literal.lit.suffix.as_ref().map(Symbol::to_string)
     }
+
     fn integer(&mut self, n: &str) -> Self::Literal {
         self.lit(token::Integer, Symbol::intern(n), None)
     }
+
     fn typed_integer(&mut self, n: &str, kind: &str) -> Self::Literal {
         self.lit(token::Integer, Symbol::intern(n), Some(Symbol::intern(kind)))
     }
+
     fn float(&mut self, n: &str) -> Self::Literal {
         self.lit(token::Float, Symbol::intern(n), None)
     }
+
     fn f32(&mut self, n: &str) -> Self::Literal {
         self.lit(token::Float, Symbol::intern(n), Some(sym::f32))
     }
+
     fn f64(&mut self, n: &str) -> Self::Literal {
         self.lit(token::Float, Symbol::intern(n), Some(sym::f64))
     }
+
     fn string(&mut self, string: &str) -> Self::Literal {
         let quoted = format!("{:?}", string);
         assert!(quoted.starts_with('"') && quoted.ends_with('"'));
         let symbol = &quoted[1..quoted.len() - 1];
         self.lit(token::Str, Symbol::intern(symbol), None)
     }
+
     fn character(&mut self, ch: char) -> Self::Literal {
         let quoted = format!("{:?}", ch);
         assert!(quoted.starts_with('\'') && quoted.ends_with('\''));
         let symbol = &quoted[1..quoted.len() - 1];
         self.lit(token::Char, Symbol::intern(symbol), None)
     }
+
     fn byte_string(&mut self, bytes: &[u8]) -> Self::Literal {
         let string = bytes
             .iter()
@@ -678,12 +719,15 @@
             .collect::<String>();
         self.lit(token::ByteStr, Symbol::intern(&string), None)
     }
+
     fn span(&mut self, literal: &Self::Literal) -> Self::Span {
         literal.span
     }
+
     fn set_span(&mut self, literal: &mut Self::Literal, span: Self::Span) {
         literal.span = span;
     }
+
     fn subspan(
         &mut self,
         literal: &Self::Literal,
@@ -726,6 +770,7 @@
     fn eq(&mut self, file1: &Self::SourceFile, file2: &Self::SourceFile) -> bool {
         Lrc::ptr_eq(file1, file2)
     }
+
     fn path(&mut self, file: &Self::SourceFile) -> String {
         match file.name {
             FileName::Real(ref name) => name
@@ -737,6 +782,7 @@
             _ => file.name.prefer_local().to_string(),
         }
     }
+
     fn is_real(&mut self, file: &Self::SourceFile) -> bool {
         file.is_real_file()
     }
@@ -746,6 +792,7 @@
     fn new(&mut self) -> Self::MultiSpan {
         vec![]
     }
+
     fn push(&mut self, spans: &mut Self::MultiSpan, span: Self::Span) {
         spans.push(span)
     }
@@ -757,6 +804,7 @@
         diag.set_span(MultiSpan::from_spans(spans));
         diag
     }
+
     fn sub(
         &mut self,
         diag: &mut Self::Diagnostic,
@@ -766,6 +814,7 @@
     ) {
         diag.sub(level.to_internal(), msg, MultiSpan::from_spans(spans), None);
     }
+
     fn emit(&mut self, mut diag: Self::Diagnostic) {
         self.sess().span_diagnostic.emit_diagnostic(&mut diag);
     }
@@ -779,38 +828,49 @@
             format!("{:?} bytes({}..{})", span.ctxt(), span.lo().0, span.hi().0)
         }
     }
+
     fn def_site(&mut self) -> Self::Span {
         self.def_site
     }
+
     fn call_site(&mut self) -> Self::Span {
         self.call_site
     }
+
     fn mixed_site(&mut self) -> Self::Span {
         self.mixed_site
     }
+
     fn source_file(&mut self, span: Self::Span) -> Self::SourceFile {
         self.sess().source_map().lookup_char_pos(span.lo()).file
     }
+
     fn parent(&mut self, span: Self::Span) -> Option<Self::Span> {
         span.parent_callsite()
     }
+
     fn source(&mut self, span: Self::Span) -> Self::Span {
         span.source_callsite()
     }
+
     fn start(&mut self, span: Self::Span) -> LineColumn {
         let loc = self.sess().source_map().lookup_char_pos(span.lo());
         LineColumn { line: loc.line, column: loc.col.to_usize() }
     }
+
     fn end(&mut self, span: Self::Span) -> LineColumn {
         let loc = self.sess().source_map().lookup_char_pos(span.hi());
         LineColumn { line: loc.line, column: loc.col.to_usize() }
     }
+
     fn before(&mut self, span: Self::Span) -> Self::Span {
         span.shrink_to_lo()
     }
+
     fn after(&mut self, span: Self::Span) -> Self::Span {
         span.shrink_to_hi()
     }
+
     fn join(&mut self, first: Self::Span, second: Self::Span) -> Option<Self::Span> {
         let self_loc = self.sess().source_map().lookup_char_pos(first.lo());
         let other_loc = self.sess().source_map().lookup_char_pos(second.lo());
@@ -821,9 +881,11 @@
 
         Some(first.to(second))
     }
+
     fn resolved_at(&mut self, span: Self::Span, at: Self::Span) -> Self::Span {
         span.with_ctxt(at.ctxt())
     }
+
     fn source_text(&mut self, span: Self::Span) -> Option<String> {
         self.sess().source_map().span_to_snippet(span).ok()
     }
@@ -854,6 +916,7 @@
     fn save_span(&mut self, span: Self::Span) -> usize {
         self.sess().save_proc_macro_span(span)
     }
+
     fn recover_proc_macro_span(&mut self, id: usize) -> Self::Span {
         let (resolver, krate, def_site) = (&*self.ecx.resolver, self.krate, self.def_site);
         *self.rebased_spans.entry(id).or_insert_with(|| {
diff --git a/compiler/rustc_expand/src/tests.rs b/compiler/rustc_expand/src/tests.rs
index 693159f..8b71537 100644
--- a/compiler/rustc_expand/src/tests.rs
+++ b/compiler/rustc_expand/src/tests.rs
@@ -22,7 +22,7 @@
     new_parser_from_source_str(ps, PathBuf::from("bogofile").into(), source_str)
 }
 
-crate fn with_error_checking_parse<'a, T, F>(s: String, ps: &'a ParseSess, f: F) -> T
+pub(crate) fn with_error_checking_parse<'a, T, F>(s: String, ps: &'a ParseSess, f: F) -> T
 where
     F: FnOnce(&mut Parser<'a>) -> PResult<'a, T>,
 {
@@ -33,7 +33,7 @@
 }
 
 /// Maps a string to tts, using a made-up filename.
-crate fn string_to_stream(source_str: String) -> TokenStream {
+pub(crate) fn string_to_stream(source_str: String) -> TokenStream {
     let ps = ParseSess::new(FilePathMapping::empty());
     source_file_to_stream(
         &ps,
@@ -44,7 +44,7 @@
 }
 
 /// Parses a string, returns a crate.
-crate fn string_to_crate(source_str: String) -> ast::Crate {
+pub(crate) fn string_to_crate(source_str: String) -> ast::Crate {
     let ps = ParseSess::new(FilePathMapping::empty());
     with_error_checking_parse(source_str, &ps, |p| p.parse_crate_mod())
 }
@@ -53,7 +53,7 @@
 /// may be deleted or replaced with other whitespace to match the pattern.
 /// This function is relatively Unicode-ignorant; fortunately, the careful design
 /// of UTF-8 mitigates this ignorance. It doesn't do NKF-normalization(?).
-crate fn matches_codepattern(a: &str, b: &str) -> bool {
+pub(crate) fn matches_codepattern(a: &str, b: &str) -> bool {
     let mut a_iter = a.chars().peekable();
     let mut b_iter = b.chars().peekable();
 
@@ -109,7 +109,7 @@
     label: &'static str,
 }
 
-crate struct Shared<T: Write> {
+pub(crate) struct Shared<T: Write> {
     pub data: Arc<Mutex<T>>,
 }
 
diff --git a/compiler/rustc_expand/src/tokenstream/tests.rs b/compiler/rustc_expand/src/tokenstream/tests.rs
index 31052bf..e4a4db2 100644
--- a/compiler/rustc_expand/src/tokenstream/tests.rs
+++ b/compiler/rustc_expand/src/tokenstream/tests.rs
@@ -4,7 +4,6 @@
 use rustc_ast::tokenstream::{Spacing, TokenStream, TokenStreamBuilder, TokenTree};
 use rustc_span::create_default_session_globals_then;
 use rustc_span::{BytePos, Span, Symbol};
-use smallvec::smallvec;
 
 fn string_to_ts(string: &str) -> TokenStream {
     string_to_stream(string.to_owned())
@@ -24,7 +23,10 @@
         let test_res = string_to_ts("foo::bar::baz");
         let test_fst = string_to_ts("foo::bar");
         let test_snd = string_to_ts("::baz");
-        let eq_res = TokenStream::from_streams(smallvec![test_fst, test_snd]);
+        let mut builder = TokenStreamBuilder::new();
+        builder.push(test_fst);
+        builder.push(test_snd);
+        let eq_res = builder.build();
         assert_eq!(test_res.trees().count(), 5);
         assert_eq!(eq_res.trees().count(), 5);
         assert_eq!(test_res.eq_unspanned(&eq_res), true);
@@ -35,7 +37,7 @@
 fn test_to_from_bijection() {
     create_default_session_globals_then(|| {
         let test_start = string_to_ts("foo::bar(baz)");
-        let test_end = test_start.trees().collect();
+        let test_end = test_start.trees().cloned().collect();
         assert_eq!(test_start, test_end)
     })
 }
diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs
index 0480393..099c40b 100644
--- a/compiler/rustc_feature/src/accepted.rs
+++ b/compiler/rustc_feature/src/accepted.rs
@@ -142,6 +142,8 @@
     (accepted, dyn_trait, "1.27.0", Some(44662), None),
     /// Allows integer match exhaustiveness checking (RFC 2591).
     (accepted, exhaustive_integer_patterns, "1.33.0", Some(50907), None),
+    /// Allows explicit generic arguments specification with `impl Trait` present.
+    (accepted, explicit_generic_args_with_impl_trait, "1.63.0", Some(83701), None),
     /// Allows arbitrary expressions in key-value attributes at parse time.
     (accepted, extended_key_value_attributes, "1.54.0", Some(78835), None),
     /// Allows resolving absolute paths as paths from other crates.
@@ -219,8 +221,12 @@
     (accepted, move_ref_pattern, "1.49.0", Some(68354), None),
     /// Allows specifying modifiers in the link attribute: `#[link(modifiers = "...")]`
     (accepted, native_link_modifiers, "1.61.0", Some(81490), None),
+    /// Allows specifying the bundle link modifier
+    (accepted, native_link_modifiers_bundle, "1.63.0", Some(81490), None),
     /// Allows specifying the whole-archive link modifier
     (accepted, native_link_modifiers_whole_archive, "1.61.0", Some(81490), None),
+    /// Allows using non lexical lifetimes (RFC 2094).
+    (accepted, nll, "1.63.0", Some(43234), None),
     /// Allows using `#![no_std]`.
     (accepted, no_std, "1.6.0", None, None),
     /// Allows defining identifiers beyond ASCII.
diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs
index 520769d..b54f0ef 100644
--- a/compiler/rustc_feature/src/active.rs
+++ b/compiler/rustc_feature/src/active.rs
@@ -150,6 +150,8 @@
     (active, allow_internal_unstable, "1.0.0", None, None),
     /// Allows identifying the `compiler_builtins` crate.
     (active, compiler_builtins, "1.13.0", None, None),
+    /// Outputs useful `assert!` messages
+    (active, generic_assert, "1.63.0", None, None),
     /// Allows using the `rust-intrinsic`'s "ABI".
     (active, intrinsics, "1.0.0", None, None),
     /// Allows using `#[lang = ".."]` attribute for linking items to special compiler logic.
@@ -319,6 +321,8 @@
     (active, cfg_sanitize, "1.41.0", Some(39699), None),
     /// Allows `cfg(target_abi = "...")`.
     (active, cfg_target_abi, "1.55.0", Some(80970), None),
+    /// Allows `cfg(target(abi = "..."))`.
+    (active, cfg_target_compact, "1.63.0", Some(96901), None),
     /// Allows `cfg(target_has_atomic_load_store = "...")`.
     (active, cfg_target_has_atomic, "1.60.0", Some(94039), None),
     /// Allows `cfg(target_has_atomic_equal_alignment = "...")`.
@@ -351,8 +355,6 @@
     (active, const_trait_impl, "1.42.0", Some(67792), None),
     /// Allows the `?` operator in const contexts.
     (active, const_try, "1.56.0", Some(74935), None),
-    /// Allows using `crate` as visibility modifier, synonymous with `pub(crate)`.
-    (active, crate_visibility_modifier, "1.23.0", Some(53120), None),
     /// Allows non-builtin attributes in inner attribute position.
     (active, custom_inner_attributes, "1.30.0", Some(54726), None),
     /// Allows custom test frameworks with `#![test_runner]` and `#[test_case]`.
@@ -381,8 +383,6 @@
     (active, exclusive_range_pattern, "1.11.0", Some(37854), None),
     /// Allows exhaustive pattern matching on types that contain uninhabited types.
     (active, exhaustive_patterns, "1.13.0", Some(51085), None),
-    /// Allows explicit generic arguments specification with `impl Trait` present.
-    (active, explicit_generic_args_with_impl_trait, "1.56.0", Some(83701), None),
     /// Allows defining `extern type`s.
     (active, extern_types, "1.23.0", Some(43467), None),
     /// Allows the use of `#[ffi_const]` on foreign functions.
@@ -409,8 +409,6 @@
     (active, if_let_guard, "1.47.0", Some(51114), None),
     /// Allows using imported `main` function
     (active, imported_main, "1.53.0", Some(28937), None),
-    /// Allows inferring `'static` outlives requirements (RFC 2093).
-    (active, infer_static_outlives_requirements, "1.26.0", Some(54185), None),
     /// Allows associated types in inherent impls.
     (incomplete, inherent_associated_types, "1.52.0", Some(8995), None),
     /// Allow anonymous constants from an inline `const` block
@@ -449,8 +447,6 @@
     (active, naked_functions, "1.9.0", Some(32408), None),
     /// Allows specifying the as-needed link modifier
     (active, native_link_modifiers_as_needed, "1.53.0", Some(81490), None),
-    /// Allows specifying the bundle link modifier
-    (active, native_link_modifiers_bundle, "1.53.0", Some(81490), None),
     /// Allows specifying the verbatim link modifier
     (active, native_link_modifiers_verbatim, "1.53.0", Some(81490), None),
     /// Allow negative trait implementations.
@@ -459,8 +455,6 @@
     (active, never_type, "1.13.0", Some(35121), None),
     /// Allows diverging expressions to fall back to `!` rather than `()`.
     (active, never_type_fallback, "1.41.0", Some(65992), None),
-    /// Allows using non lexical lifetimes (RFC 2094).
-    (active, nll, "1.0.0", Some(43234), None),
     /// Allows `#![no_core]`.
     (active, no_core, "1.3.0", Some(29639), None),
     /// Allows function attribute `#[no_coverage]`, to bypass coverage
@@ -496,12 +490,12 @@
     (incomplete, repr128, "1.16.0", Some(56071), None),
     /// Allows `repr(simd)` and importing the various simd intrinsics.
     (active, repr_simd, "1.4.0", Some(27731), None),
+    /// Allows `extern "rust-cold"`.
+    (active, rust_cold_cc, "1.63.0", Some(97544), None),
     /// Allows the use of SIMD types in functions declared in `extern` blocks.
     (active, simd_ffi, "1.0.0", Some(27731), None),
     /// Allows specialization of implementations (RFC 1210).
     (incomplete, specialization, "1.7.0", Some(31844), None),
-    /// Allows `#[link(kind="static-nobundle"...)]`.
-    (active, static_nobundle, "1.16.0", Some(37403), None),
     /// Allows attributes on expressions and non-item statements.
     (active, stmt_expr_attributes, "1.6.0", Some(15701), None),
     /// Allows lints part of the strict provenance effort.
@@ -527,7 +521,7 @@
     (active, type_ascription, "1.6.0", Some(23416), None),
     /// Allows creation of instances of a struct by moving fields that have
     /// not changed from prior instances of the same struct (RFC #2528)
-    (incomplete, type_changing_struct_update, "1.58.0", Some(86555), None),
+    (active, type_changing_struct_update, "1.58.0", Some(86555), None),
     /// Allows unsized fn parameters.
     (active, unsized_fn_params, "1.49.0", Some(48055), None),
     /// Allows unsized rvalues at arguments and parameters.
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index 097493e..6fcdfe4 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -9,7 +9,7 @@
 use rustc_data_structures::fx::FxHashMap;
 use rustc_span::symbol::{sym, Symbol};
 
-use std::lazy::SyncLazy;
+use std::sync::LazyLock;
 
 type GateFn = fn(&Features) -> bool;
 
@@ -399,7 +399,7 @@
 
     // RFC #3191: #[debugger_visualizer] support
     gated!(
-        debugger_visualizer, Normal, template!(List: r#"natvis_file = "...""#),
+        debugger_visualizer, Normal, template!(List: r#"natvis_file = "...", gdb_script_file = "...""#),
         DuplicatesOk, experimental!(debugger_visualizer)
     ),
 
@@ -473,9 +473,10 @@
     ),
     // RFC 2632
     gated!(
-        default_method_body_is_const, Normal, template!(Word), WarnFollowing, const_trait_impl,
-        "`default_method_body_is_const` is a temporary placeholder for declaring default bodies \
-        as `const`, which may be removed or renamed in the future."
+        const_trait, Normal, template!(Word), WarnFollowing, const_trait_impl,
+        "`const` is a temporary placeholder for marking a trait that is suitable for `const` \
+        `impls` and all default bodies as `const`, which may be removed or renamed in the \
+        future."
     ),
     // lang-team MCP 147
     gated!(
@@ -488,11 +489,6 @@
     // ==========================================================================
 
     ungated!(feature, CrateLevel, template!(List: "name1, name2, ..."), DuplicatesOk),
-    // FIXME(jhpratt) remove this eventually
-    ungated!(
-        rustc_deprecated, Normal,
-        template!(List: r#"since = "version", note = "...""#), ErrorFollowing
-    ),
     // DuplicatesOk since it has its own validation
     ungated!(
         stable, Normal, template!(List: r#"feature = "name", since = "version""#), DuplicatesOk,
@@ -614,6 +610,9 @@
     // Used by the `rustc::potential_query_instability` lint to warn methods which
     // might not be stable during incremental compilation.
     rustc_attr!(rustc_lint_query_instability, Normal, template!(Word), WarnFollowing, INTERNAL_UNSTABLE),
+    // Used by the `rustc::untranslatable_diagnostic` and `rustc::diagnostic_outside_of_impl` lints
+    // to assist in changes to diagnostic APIs.
+    rustc_attr!(rustc_lint_diagnostics, Normal, template!(Word), WarnFollowing, INTERNAL_UNSTABLE),
 
     // ==========================================================================
     // Internal attributes, Const related:
@@ -674,6 +673,12 @@
         "#[rustc_has_incoherent_inherent_impls] allows the addition of incoherent inherent impls for \
          the given type by annotating all impl items with #[rustc_allow_incoherent_impl]."
     ),
+    rustc_attr!(
+        rustc_box, AttributeType::Normal, template!(Word), ErrorFollowing,
+        "#[rustc_box] allows creating boxes \
+        and it is only intended to be used in `alloc`."
+    ),
+
     BuiltinAttribute {
         name: sym::rustc_diagnostic_item,
         // FIXME: This can be `true` once we always use `tcx.is_diagnostic_item`.
@@ -804,8 +809,8 @@
     BUILTIN_ATTRIBUTE_MAP.get(&name).map_or(false, |attr| attr.only_local)
 }
 
-pub static BUILTIN_ATTRIBUTE_MAP: SyncLazy<FxHashMap<Symbol, &BuiltinAttribute>> =
-    SyncLazy::new(|| {
+pub static BUILTIN_ATTRIBUTE_MAP: LazyLock<FxHashMap<Symbol, &BuiltinAttribute>> =
+    LazyLock::new(|| {
         let mut map = FxHashMap::default();
         for attr in BUILTIN_ATTRIBUTES.iter() {
             if map.insert(attr.name, attr).is_some() {
diff --git a/compiler/rustc_feature/src/lib.rs b/compiler/rustc_feature/src/lib.rs
index 26e0538..efb8305 100644
--- a/compiler/rustc_feature/src/lib.rs
+++ b/compiler/rustc_feature/src/lib.rs
@@ -11,7 +11,6 @@
 //! even if it is stabilized or removed, *do not remove it*. Instead, move the
 //! symbol to the `accepted` or `removed` modules respectively.
 
-#![cfg_attr(bootstrap, feature(derive_default_enum))]
 #![feature(once_cell)]
 
 mod accepted;
diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs
index fae9bd6..54626ca 100644
--- a/compiler/rustc_feature/src/removed.rs
+++ b/compiler/rustc_feature/src/removed.rs
@@ -72,6 +72,8 @@
     /// Allows `T: ?const Trait` syntax in bounds.
     (removed, const_trait_bound_opt_out, "1.42.0", Some(67794), None,
      Some("Removed in favor of `~const` bound in #![feature(const_trait_impl)]")),
+    /// Allows using `crate` as visibility modifier, synonymous with `pub(crate)`.
+    (removed, crate_visibility_modifier, "1.63.0", Some(53120), None, Some("removed in favor of `pub(crate)`")),
     /// Allows using custom attributes (RFC 572).
     (removed, custom_attribute, "1.0.0", Some(29642), None,
      Some("removed in favor of `#![register_tool]` and `#![register_attr]`")),
@@ -107,6 +109,9 @@
     /// Allows in-band quantification of lifetime bindings (e.g., `fn foo(x: &'a u8) -> &'a u8`).
     (removed, in_band_lifetimes, "1.23.0", Some(44524), None,
      Some("removed due to unsolved ergonomic questions and added lifetime resolution complexity")),
+    /// Allows inferring `'static` outlives requirements (RFC 2093).
+    (removed, infer_static_outlives_requirements, "1.63.0", Some(54185), None,
+     Some("removed as it caused some confusion and discussion was inactive for years")),
     /// Lazily evaluate constants. This allows constants to depend on type parameters.
     (removed, lazy_normalization_consts, "1.46.0", Some(72219), None, Some("superseded by `generic_const_exprs`")),
     /// Allows using the `#[link_args]` attribute.
@@ -167,6 +172,9 @@
     (removed, sanitizer_runtime, "1.17.0", None, None, None),
     (removed, simd, "1.0.0", Some(27731), None,
      Some("removed in favor of `#[repr(simd)]`")),
+    /// Allows `#[link(kind = "static-nobundle", ...)]`.
+    (removed, static_nobundle, "1.16.0", Some(37403), None,
+     Some(r#"subsumed by `#[link(kind = "static", modifiers = "-bundle", ...)]`"#)),
     (removed, struct_inherit, "1.0.0", None, None, None),
     (removed, test_removed_feature, "1.0.0", None, None, None),
     /// Allows using items which are missing stability attributes
diff --git a/compiler/rustc_graphviz/src/lib.rs b/compiler/rustc_graphviz/src/lib.rs
index 676c66f..6eaff5c 100644
--- a/compiler/rustc_graphviz/src/lib.rs
+++ b/compiler/rustc_graphviz/src/lib.rs
@@ -273,7 +273,6 @@
     html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/",
     test(attr(allow(unused_variables), deny(warnings)))
 )]
-#![feature(nll)]
 
 use LabelText::*;
 
diff --git a/compiler/rustc_hir/Cargo.toml b/compiler/rustc_hir/Cargo.toml
index 34d366f..47ace7c 100644
--- a/compiler/rustc_hir/Cargo.toml
+++ b/compiler/rustc_hir/Cargo.toml
@@ -8,7 +8,6 @@
 
 [dependencies]
 rustc_target = { path = "../rustc_target" }
-rustc_feature = { path = "../rustc_feature" }
 rustc_macros = { path = "../rustc_macros" }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_error_messages = { path = "../rustc_error_messages" }
diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs
index a639df0..d0893cd 100644
--- a/compiler/rustc_hir/src/def.rs
+++ b/compiler/rustc_hir/src/def.rs
@@ -1,9 +1,9 @@
-use crate::def_id::DefId;
 use crate::hir;
 
 use rustc_ast as ast;
 use rustc_ast::NodeId;
 use rustc_macros::HashStable_Generic;
+use rustc_span::def_id::{DefId, LocalDefId};
 use rustc_span::hygiene::MacroKind;
 use rustc_span::Symbol;
 
@@ -92,6 +92,7 @@
     /// [RFC 2593]: https://github.com/rust-lang/rfcs/pull/2593
     Ctor(CtorOf, CtorKind),
     /// Associated function: `impl MyStruct { fn associated() {} }`
+    /// or `trait Foo { fn associated() {} }`
     AssocFn,
     /// Associated constant: `trait MyTrait { const ASSOC: usize; }`
     AssocConst,
@@ -670,7 +671,10 @@
 
     #[track_caller]
     pub fn expect_non_local<OtherId>(self) -> Res<OtherId> {
-        self.map_id(|_| panic!("unexpected `Res::Local`"))
+        self.map_id(
+            #[track_caller]
+            |_| panic!("unexpected `Res::Local`"),
+        )
     }
 
     pub fn macro_kind(self) -> Option<MacroKind> {
@@ -707,3 +711,44 @@
         matches!(self, Res::Def(DefKind::Ctor(_, CtorKind::Const), _) | Res::SelfCtor(..))
     }
 }
+
+/// Resolution for a lifetime appearing in a type.
+#[derive(Copy, Clone, Debug)]
+pub enum LifetimeRes {
+    /// Successfully linked the lifetime to a generic parameter.
+    Param {
+        /// Id of the generic parameter that introduced it.
+        param: LocalDefId,
+        /// Id of the introducing place. That can be:
+        /// - an item's id, for the item's generic parameters;
+        /// - a TraitRef's ref_id, identifying the `for<...>` binder;
+        /// - a BareFn type's id.
+        ///
+        /// This information is used for impl-trait lifetime captures, to know when to or not to
+        /// capture any given lifetime.
+        binder: NodeId,
+    },
+    /// Created a generic parameter for an anonymous lifetime.
+    Fresh {
+        /// Id of the generic parameter that introduced it.
+        ///
+        /// Creating the associated `LocalDefId` is the responsibility of lowering.
+        param: NodeId,
+        /// Id of the introducing place. See `Param`.
+        binder: NodeId,
+    },
+    /// This variant is used for anonymous lifetimes that we did not resolve during
+    /// late resolution.  Shifting the work to the HIR lifetime resolver.
+    Anonymous {
+        /// Id of the introducing place. See `Param`.
+        binder: NodeId,
+        /// Whether this lifetime was spelled or elided.
+        elided: bool,
+    },
+    /// Explicit `'static` lifetime.
+    Static,
+    /// Resolution failure.
+    Error,
+    /// HACK: This is used to recover the NodeId of an elided lifetime.
+    ElidedAnchor { start: NodeId, end: NodeId },
+}
diff --git a/compiler/rustc_hir/src/definitions.rs b/compiler/rustc_hir/src/definitions.rs
index 5c32dd3..5f8801c 100644
--- a/compiler/rustc_hir/src/definitions.rs
+++ b/compiler/rustc_hir/src/definitions.rs
@@ -11,9 +11,7 @@
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::stable_hasher::StableHasher;
 use rustc_index::vec::IndexVec;
-use rustc_span::hygiene::ExpnId;
 use rustc_span::symbol::{kw, sym, Symbol};
-use rustc_span::Span;
 
 use std::fmt::{self, Write};
 use std::hash::Hash;
@@ -101,11 +99,6 @@
     table: DefPathTable,
     next_disambiguator: FxHashMap<(LocalDefId, DefPathData), u32>,
 
-    /// Item with a given `LocalDefId` was defined during macro expansion with ID `ExpnId`.
-    expansions_that_defined: FxHashMap<LocalDefId, ExpnId>,
-
-    def_id_to_span: IndexVec<LocalDefId, Span>,
-
     /// The [StableCrateId] of the local crate.
     stable_crate_id: StableCrateId,
 }
@@ -323,7 +316,7 @@
     }
 
     /// Adds a root definition (no parent) and a few other reserved definitions.
-    pub fn new(stable_crate_id: StableCrateId, crate_span: Span) -> Definitions {
+    pub fn new(stable_crate_id: StableCrateId) -> Definitions {
         let key = DefKey {
             parent: None,
             disambiguated_data: DisambiguatedDefPathData {
@@ -340,30 +333,12 @@
         let root = LocalDefId { local_def_index: table.allocate(key, def_path_hash) };
         assert_eq!(root.local_def_index, CRATE_DEF_INDEX);
 
-        let mut def_id_to_span = IndexVec::new();
-        // A relative span's parent must be an absolute span.
-        debug_assert_eq!(crate_span.data_untracked().parent, None);
-        let _root = def_id_to_span.push(crate_span);
-        debug_assert_eq!(_root, root);
-
-        Definitions {
-            table,
-            next_disambiguator: Default::default(),
-            expansions_that_defined: Default::default(),
-            def_id_to_span,
-            stable_crate_id,
-        }
+        Definitions { table, next_disambiguator: Default::default(), stable_crate_id }
     }
 
     /// Adds a definition with a parent definition.
-    pub fn create_def(
-        &mut self,
-        parent: LocalDefId,
-        data: DefPathData,
-        expn_id: ExpnId,
-        span: Span,
-    ) -> LocalDefId {
-        debug!("create_def(parent={:?}, data={:?}, expn_id={:?})", parent, data, expn_id);
+    pub fn create_def(&mut self, parent: LocalDefId, data: DefPathData) -> LocalDefId {
+        debug!("create_def(parent={:?}, data={:?})", parent, data);
 
         // The root node must be created with `create_root_def()`.
         assert!(data != DefPathData::CrateRoot);
@@ -386,28 +361,7 @@
         debug!("create_def: after disambiguation, key = {:?}", key);
 
         // Create the definition.
-        let def_id = LocalDefId { local_def_index: self.table.allocate(key, def_path_hash) };
-
-        if expn_id != ExpnId::root() {
-            self.expansions_that_defined.insert(def_id, expn_id);
-        }
-
-        // A relative span's parent must be an absolute span.
-        debug_assert_eq!(span.data_untracked().parent, None);
-        let _id = self.def_id_to_span.push(span);
-        debug_assert_eq!(_id, def_id);
-
-        def_id
-    }
-
-    pub fn expansion_that_defined(&self, id: LocalDefId) -> ExpnId {
-        self.expansions_that_defined.get(&id).copied().unwrap_or_else(ExpnId::root)
-    }
-
-    /// Retrieves the span of the given `DefId` if `DefId` is in the local crate.
-    #[inline]
-    pub fn def_span(&self, def_id: LocalDefId) -> Span {
-        self.def_id_to_span[def_id]
+        LocalDefId { local_def_index: self.table.allocate(key, def_path_hash) }
     }
 
     pub fn iter_local_def_id(&self) -> impl Iterator<Item = LocalDefId> + '_ {
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index dc88d86..a7fc592 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -1,6 +1,6 @@
 use crate::def::{CtorKind, DefKind, Res};
 use crate::def_id::DefId;
-crate use crate::hir_id::{HirId, ItemLocalId};
+pub(crate) use crate::hir_id::{HirId, ItemLocalId};
 use crate::intravisit::FnKind;
 use crate::LangItem;
 
@@ -26,7 +26,7 @@
 use smallvec::SmallVec;
 use std::fmt;
 
-#[derive(Copy, Clone, Encodable, HashStable_Generic)]
+#[derive(Debug, Copy, Clone, Encodable, HashStable_Generic)]
 pub struct Lifetime {
     pub hir_id: HirId,
     pub span: Span,
@@ -60,7 +60,7 @@
     /// ```
     /// where `'f` is something like `Fresh(0)`. The indices are
     /// unique per impl, but not necessarily continuous.
-    Fresh(LocalDefId),
+    Fresh,
 
     /// Indicates an illegal name was given and an error has been
     /// reported (so we should squelch other derived errors). Occurs
@@ -72,9 +72,7 @@
     pub fn ident(&self) -> Ident {
         match *self {
             ParamName::Plain(ident) => ident,
-            ParamName::Fresh(_) | ParamName::Error => {
-                Ident::with_dummy_span(kw::UnderscoreLifetime)
-            }
+            ParamName::Fresh | ParamName::Error => Ident::with_dummy_span(kw::UnderscoreLifetime),
         }
     }
 
@@ -90,7 +88,7 @@
 #[derive(HashStable_Generic)]
 pub enum LifetimeName {
     /// User-given names or fresh (synthetic) names.
-    Param(ParamName),
+    Param(LocalDefId, ParamName),
 
     /// User wrote nothing (e.g., the lifetime in `&u32`).
     Implicit,
@@ -127,7 +125,18 @@
             | LifetimeName::Error => Ident::empty(),
             LifetimeName::Underscore => Ident::with_dummy_span(kw::UnderscoreLifetime),
             LifetimeName::Static => Ident::with_dummy_span(kw::StaticLifetime),
-            LifetimeName::Param(param_name) => param_name.ident(),
+            LifetimeName::Param(_, param_name) => param_name.ident(),
+        }
+    }
+
+    pub fn is_anonymous(&self) -> bool {
+        match *self {
+            LifetimeName::ImplicitObjectLifetimeDefault
+            | LifetimeName::Implicit
+            | LifetimeName::Underscore
+            | LifetimeName::Param(_, ParamName::Fresh)
+            | LifetimeName::Error => true,
+            LifetimeName::Static | LifetimeName::Param(..) => false,
         }
     }
 
@@ -137,12 +146,12 @@
             | LifetimeName::Implicit
             | LifetimeName::Underscore => true,
 
-            // It might seem surprising that `Fresh(_)` counts as
+            // It might seem surprising that `Fresh` counts as
             // *not* elided -- but this is because, as far as the code
-            // in the compiler is concerned -- `Fresh(_)` variants act
+            // in the compiler is concerned -- `Fresh` variants act
             // equivalently to "some fresh name". They correspond to
             // early-bound regions on an impl, in other words.
-            LifetimeName::Error | LifetimeName::Param(_) | LifetimeName::Static => false,
+            LifetimeName::Error | LifetimeName::Param(..) | LifetimeName::Static => false,
         }
     }
 
@@ -152,8 +161,8 @@
 
     pub fn normalize_to_macros_2_0(&self) -> LifetimeName {
         match *self {
-            LifetimeName::Param(param_name) => {
-                LifetimeName::Param(param_name.normalize_to_macros_2_0())
+            LifetimeName::Param(def_id, param_name) => {
+                LifetimeName::Param(def_id, param_name.normalize_to_macros_2_0())
             }
             lifetime_name => lifetime_name,
         }
@@ -166,12 +175,6 @@
     }
 }
 
-impl fmt::Debug for Lifetime {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "lifetime({}: {})", self.hir_id, self.name.ident())
-    }
-}
-
 impl Lifetime {
     pub fn is_elided(&self) -> bool {
         self.name.is_elided()
@@ -343,12 +346,12 @@
     pub span_ext: Span,
 }
 
-impl GenericArgs<'_> {
+impl<'hir> GenericArgs<'hir> {
     pub const fn none() -> Self {
         Self { args: &[], bindings: &[], parenthesized: false, span_ext: DUMMY_SP }
     }
 
-    pub fn inputs(&self) -> &[Ty<'_>] {
+    pub fn inputs(&self) -> &[Ty<'hir>] {
         if self.parenthesized {
             for arg in self.args {
                 match arg {
@@ -532,7 +535,7 @@
 pub struct Generics<'hir> {
     pub params: &'hir [GenericParam<'hir>],
     pub predicates: &'hir [WherePredicate<'hir>],
-    pub has_where_clause: bool,
+    pub has_where_clause_predicates: bool,
     pub where_clause_span: Span,
     pub span: Span,
 }
@@ -542,14 +545,14 @@
         const NOPE: Generics<'_> = Generics {
             params: &[],
             predicates: &[],
-            has_where_clause: false,
+            has_where_clause_predicates: false,
             where_clause_span: DUMMY_SP,
             span: DUMMY_SP,
         };
         &NOPE
     }
 
-    pub fn get_named(&self, name: Symbol) -> Option<&GenericParam<'_>> {
+    pub fn get_named(&self, name: Symbol) -> Option<&GenericParam<'hir>> {
         for param in self.params {
             if name == param.name.ident().name {
                 return Some(param);
@@ -578,21 +581,11 @@
         }
     }
 
-    pub fn where_clause_span(&self) -> Option<Span> {
-        if self.predicates.is_empty() { None } else { Some(self.where_clause_span) }
-    }
-
-    /// The `where_span` under normal circumstances points at either the predicates or the empty
-    /// space where the `where` clause should be. Only of use for diagnostic suggestions.
-    pub fn span_for_predicates_or_empty_place(&self) -> Span {
-        self.where_clause_span
-    }
-
     /// `Span` where further predicates would be suggested, accounting for trailing commas, like
     ///  in `fn foo<T>(t: T) where T: Foo,` so we don't suggest two trailing commas.
     pub fn tail_span_for_predicate_suggestion(&self) -> Span {
-        let end = self.span_for_predicates_or_empty_place().shrink_to_hi();
-        if self.has_where_clause {
+        let end = self.where_clause_span.shrink_to_hi();
+        if self.has_where_clause_predicates {
             self.predicates
                 .iter()
                 .filter(|p| p.in_where_clause())
@@ -605,10 +598,21 @@
         }
     }
 
+    pub fn add_where_or_trailing_comma(&self) -> &'static str {
+        if self.has_where_clause_predicates {
+            ","
+        } else if self.where_clause_span.is_empty() {
+            " where"
+        } else {
+            // No where clause predicates, but we have `where` token
+            ""
+        }
+    }
+
     pub fn bounds_for_param(
         &self,
         param_def_id: LocalDefId,
-    ) -> impl Iterator<Item = &WhereBoundPredicate<'_>> {
+    ) -> impl Iterator<Item = &WhereBoundPredicate<'hir>> {
         self.predicates.iter().filter_map(move |pred| match pred {
             WherePredicate::BoundPredicate(bp) if bp.is_param_bound(param_def_id.to_def_id()) => {
                 Some(bp)
@@ -617,6 +621,16 @@
         })
     }
 
+    pub fn outlives_for_param(
+        &self,
+        param_def_id: LocalDefId,
+    ) -> impl Iterator<Item = &WhereRegionPredicate<'_>> {
+        self.predicates.iter().filter_map(move |pred| match pred {
+            WherePredicate::RegionPredicate(rp) if rp.is_param_bound(param_def_id) => Some(rp),
+            _ => None,
+        })
+    }
+
     pub fn bounds_span_for_suggestions(&self, param_def_id: LocalDefId) -> Option<Span> {
         self.bounds_for_param(param_def_id).flat_map(|bp| bp.bounds.iter().rev()).find_map(
             |bound| {
@@ -758,6 +772,16 @@
     pub bounds: GenericBounds<'hir>,
 }
 
+impl<'hir> WhereRegionPredicate<'hir> {
+    /// Returns `true` if `param_def_id` matches the `lifetime` of this predicate.
+    pub fn is_param_bound(&self, param_def_id: LocalDefId) -> bool {
+        match self.lifetime.name {
+            LifetimeName::Param(id, _) => id == param_def_id,
+            _ => false,
+        }
+    }
+}
+
 /// An equality predicate (e.g., `T = int`); currently unsupported.
 #[derive(Debug, HashStable_Generic)]
 pub struct WhereEqPredicate<'hir> {
@@ -796,7 +820,6 @@
 /// Map of all HIR nodes inside the current owner.
 /// These nodes are mapped by `ItemLocalId` alongside the index of their parent node.
 /// The HIR tree, including bodies, is pre-hashed.
-#[derive(Debug)]
 pub struct OwnerNodes<'tcx> {
     /// Pre-computed hash of the full HIR.
     pub hash_including_bodies: Fingerprint,
@@ -822,6 +845,18 @@
     }
 }
 
+impl fmt::Debug for OwnerNodes<'_> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_struct("OwnerNodes")
+            .field("node", &self.nodes[ItemLocalId::from_u32(0)])
+            .field("bodies", &self.bodies)
+            .field("local_id_to_def_id", &self.local_id_to_def_id)
+            .field("hash_without_bodies", &self.hash_without_bodies)
+            .field("hash_including_bodies", &self.hash_including_bodies)
+            .finish()
+    }
+}
+
 /// Full information resulting from lowering an AST node.
 #[derive(Debug, HashStable_Generic)]
 pub struct OwnerInfo<'hir> {
@@ -1320,8 +1355,21 @@
 #[derive(Debug, HashStable_Generic)]
 pub enum Guard<'hir> {
     If(&'hir Expr<'hir>),
-    // FIXME use hir::Let for this.
-    IfLet(&'hir Pat<'hir>, &'hir Expr<'hir>),
+    IfLet(&'hir Let<'hir>),
+}
+
+impl<'hir> Guard<'hir> {
+    /// Returns the body of the guard
+    ///
+    /// In other words, returns the e in either of the following:
+    ///
+    /// - `if e`
+    /// - `if let x = e`
+    pub fn body(&self) -> &'hir Expr<'hir> {
+        match self {
+            Guard::If(e) | Guard::IfLet(Let { init: e, .. }) => e,
+        }
+    }
 }
 
 #[derive(Debug, HashStable_Generic)]
@@ -1346,7 +1394,7 @@
     UserProvided,
 }
 
-#[derive(Copy, Clone, PartialEq, Eq, Encodable, Hash, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Hash, Debug)]
 pub struct BodyId {
     pub hir_id: HirId,
 }
@@ -1604,7 +1652,7 @@
             ExprKind::Let(..) => ExprPrecedence::Let,
             ExprKind::Loop(..) => ExprPrecedence::Loop,
             ExprKind::Match(..) => ExprPrecedence::Match,
-            ExprKind::Closure(..) => ExprPrecedence::Closure,
+            ExprKind::Closure { .. } => ExprPrecedence::Closure,
             ExprKind::Block(..) => ExprPrecedence::Block,
             ExprKind::Assign(..) => ExprPrecedence::Assign,
             ExprKind::AssignOp(..) => ExprPrecedence::AssignOp,
@@ -1664,7 +1712,7 @@
             | ExprKind::Tup(..)
             | ExprKind::If(..)
             | ExprKind::Match(..)
-            | ExprKind::Closure(..)
+            | ExprKind::Closure { .. }
             | ExprKind::Block(..)
             | ExprKind::Repeat(..)
             | ExprKind::Array(..)
@@ -1747,7 +1795,7 @@
             | ExprKind::Match(..)
             | ExprKind::MethodCall(..)
             | ExprKind::Call(..)
-            | ExprKind::Closure(..)
+            | ExprKind::Closure { .. }
             | ExprKind::Block(..)
             | ExprKind::Repeat(..)
             | ExprKind::Break(..)
@@ -1766,6 +1814,20 @@
             | ExprKind::Err => true,
         }
     }
+
+    // To a first-order approximation, is this a pattern
+    pub fn is_approximately_pattern(&self) -> bool {
+        match &self.kind {
+            ExprKind::Box(_)
+            | ExprKind::Array(_)
+            | ExprKind::Call(..)
+            | ExprKind::Tup(_)
+            | ExprKind::Lit(_)
+            | ExprKind::Path(_)
+            | ExprKind::Struct(..) => true,
+            _ => false,
+        }
+    }
 }
 
 /// Checks if the specified expression is a built-in range literal.
@@ -1824,7 +1886,7 @@
     /// To resolve the called method to a `DefId`, call [`type_dependent_def_id`] with
     /// the `hir_id` of the `MethodCall` node itself.
     ///
-    /// [`type_dependent_def_id`]: ../ty/struct.TypeckResults.html#method.type_dependent_def_id
+    /// [`type_dependent_def_id`]: ../../rustc_middle/ty/struct.TypeckResults.html#method.type_dependent_def_id
     MethodCall(&'hir PathSegment<'hir>, &'hir [Expr<'hir>], Span),
     /// A tuple (e.g., `(a, b, c, d)`).
     Tup(&'hir [Expr<'hir>]),
@@ -1868,7 +1930,14 @@
     ///
     /// This may also be a generator literal or an `async block` as indicated by the
     /// `Option<Movability>`.
-    Closure(CaptureBy, &'hir FnDecl<'hir>, BodyId, Span, Option<Movability>),
+    Closure {
+        capture_clause: CaptureBy,
+        bound_generic_params: &'hir [GenericParam<'hir>],
+        fn_decl: &'hir FnDecl<'hir>,
+        body: BodyId,
+        fn_decl_span: Span,
+        movability: Option<Movability>,
+    },
     /// A block (e.g., `'label: { ... }`).
     Block(&'hir Block<'hir>, Option<Label>),
 
@@ -1921,7 +1990,7 @@
 ///
 /// To resolve the path to a `DefId`, call [`qpath_res`].
 ///
-/// [`qpath_res`]: ../rustc_middle/ty/struct.TypeckResults.html#method.qpath_res
+/// [`qpath_res`]: ../../rustc_middle/ty/struct.TypeckResults.html#method.qpath_res
 #[derive(Debug, HashStable_Generic)]
 pub enum QPath<'hir> {
     /// Path to a definition, optionally "fully-qualified" with a `Self`
@@ -2129,7 +2198,7 @@
 // The bodies for items are stored "out of line", in a separate
 // hashmap in the `Crate`. Here we just record the hir-id of the item
 // so it can fetched later.
-#[derive(Copy, Clone, PartialEq, Eq, Encodable, Debug, HashStable_Generic)]
+#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug, HashStable_Generic)]
 pub struct TraitItemId {
     pub def_id: LocalDefId,
 }
@@ -2192,7 +2261,7 @@
 // The bodies for items are stored "out of line", in a separate
 // hashmap in the `Crate`. Here we just record the hir-id of the item
 // so it can fetched later.
-#[derive(Copy, Clone, PartialEq, Eq, Encodable, Debug, HashStable_Generic)]
+#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug, HashStable_Generic)]
 pub struct ImplItemId {
     pub def_id: LocalDefId,
 }
@@ -2787,7 +2856,7 @@
 // The bodies for items are stored "out of line", in a separate
 // hashmap in the `Crate`. Here we just record the hir-id of the item
 // so it can fetched later.
-#[derive(Copy, Clone, PartialEq, Eq, Encodable, Debug, Hash, HashStable_Generic)]
+#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug, Hash, HashStable_Generic)]
 pub struct ItemId {
     pub def_id: LocalDefId,
 }
@@ -2957,13 +3026,12 @@
         Some(match *self {
             ItemKind::Fn(_, ref generics, _)
             | ItemKind::TyAlias(_, ref generics)
-            | ItemKind::OpaqueTy(OpaqueTy {
-                ref generics, origin: OpaqueTyOrigin::TyAlias, ..
-            })
+            | ItemKind::OpaqueTy(OpaqueTy { ref generics, .. })
             | ItemKind::Enum(_, ref generics)
             | ItemKind::Struct(_, ref generics)
             | ItemKind::Union(_, ref generics)
             | ItemKind::Trait(_, _, ref generics, _, _)
+            | ItemKind::TraitAlias(ref generics, _)
             | ItemKind::Impl(Impl { ref generics, .. }) => generics,
             _ => return None,
         })
@@ -3034,7 +3102,7 @@
 // The bodies for items are stored "out of line", in a separate
 // hashmap in the `Crate`. Here we just record the hir-id of the item
 // so it can fetched later.
-#[derive(Copy, Clone, PartialEq, Eq, Encodable, Debug, HashStable_Generic)]
+#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug, HashStable_Generic)]
 pub struct ForeignItemId {
     pub def_id: LocalDefId,
 }
@@ -3163,13 +3231,8 @@
         }
     }
 
-    pub fn generics(&self) -> Option<&'hir Generics<'hir>> {
-        match self {
-            OwnerNode::TraitItem(TraitItem { generics, .. })
-            | OwnerNode::ImplItem(ImplItem { generics, .. }) => Some(generics),
-            OwnerNode::Item(item) => item.kind.generics(),
-            _ => None,
-        }
+    pub fn generics(self) -> Option<&'hir Generics<'hir>> {
+        Node::generics(self.into())
     }
 
     pub fn def_id(self) -> LocalDefId {
@@ -3261,6 +3324,7 @@
     Stmt(&'hir Stmt<'hir>),
     PathSegment(&'hir PathSegment<'hir>),
     Ty(&'hir Ty<'hir>),
+    TypeBinding(&'hir TypeBinding<'hir>),
     TraitRef(&'hir TraitRef<'hir>),
     Binding(&'hir Pat<'hir>),
     Pat(&'hir Pat<'hir>),
@@ -3306,6 +3370,7 @@
             | Node::PathSegment(PathSegment { ident, .. }) => Some(*ident),
             Node::Lifetime(lt) => Some(lt.name.ident()),
             Node::GenericParam(p) => Some(p.name.ident()),
+            Node::TypeBinding(b) => Some(b.ident),
             Node::Param(..)
             | Node::AnonConst(..)
             | Node::Expr(..)
@@ -3356,9 +3421,12 @@
         }
     }
 
-    pub fn generics(&self) -> Option<&'hir Generics<'hir>> {
+    pub fn generics(self) -> Option<&'hir Generics<'hir>> {
         match self {
-            Node::TraitItem(TraitItem { generics, .. })
+            Node::ForeignItem(ForeignItem {
+                kind: ForeignItemKind::Fn(_, _, generics), ..
+            })
+            | Node::TraitItem(TraitItem { generics, .. })
             | Node::ImplItem(ImplItem { generics, .. }) => Some(generics),
             Node::Item(item) => item.kind.generics(),
             _ => None,
@@ -3395,7 +3463,7 @@
                 _ => None,
             },
             Node::Expr(e) => match e.kind {
-                ExprKind::Closure(..) => Some(FnKind::Closure),
+                ExprKind::Closure { .. } => Some(FnKind::Closure),
                 _ => None,
             },
             _ => None,
@@ -3413,7 +3481,7 @@
 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
 mod size_asserts {
     rustc_data_structures::static_assert_size!(super::Block<'static>, 48);
-    rustc_data_structures::static_assert_size!(super::Expr<'static>, 56);
+    rustc_data_structures::static_assert_size!(super::Expr<'static>, 64);
     rustc_data_structures::static_assert_size!(super::Pat<'static>, 88);
     rustc_data_structures::static_assert_size!(super::QPath<'static>, 24);
     rustc_data_structures::static_assert_size!(super::Ty<'static>, 72);
diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs
index 977c0eb..e68274e 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -1,7 +1,40 @@
 //! HIR walker for walking the contents of nodes.
 //!
-//! **For an overview of the visitor strategy, see the docs on the
-//! `super::itemlikevisit::ItemLikeVisitor` trait.**
+//! Here are the three available patterns for the visitor strategy,
+//! in roughly the order of desirability:
+//!
+//! 1. **Shallow visit**: Get a simple callback for every item (or item-like thing) in the HIR.
+//!    - Example: find all items with a `#[foo]` attribute on them.
+//!    - How: Use the `hir_crate_items` or `hir_module_items` query to traverse over item-like ids
+//!       (ItemId, TraitItemId, etc.) and use tcx.def_kind and `tcx.hir().item*(id)` to filter and
+//!       access actual item-like thing, respectively.
+//!    - Pro: Efficient; just walks the lists of item ids and gives users control whether to access
+//!       the hir_owners themselves or not.
+//!    - Con: Don't get information about nesting
+//!    - Con: Don't have methods for specific bits of HIR, like "on
+//!      every expr, do this".
+//! 2. **Deep visit**: Want to scan for specific kinds of HIR nodes within
+//!    an item, but don't care about how item-like things are nested
+//!    within one another.
+//!    - Example: Examine each expression to look for its type and do some check or other.
+//!    - How: Implement `intravisit::Visitor` and override the `NestedFilter` type to
+//!      `nested_filter::OnlyBodies` (and implement `nested_visit_map`), and use
+//!      `tcx.hir().deep_visit_all_item_likes(&mut visitor)`. Within your
+//!      `intravisit::Visitor` impl, implement methods like `visit_expr()` (don't forget to invoke
+//!      `intravisit::walk_expr()` to keep walking the subparts).
+//!    - Pro: Visitor methods for any kind of HIR node, not just item-like things.
+//!    - Pro: Integrates well into dependency tracking.
+//!    - Con: Don't get information about nesting between items
+//! 3. **Nested visit**: Want to visit the whole HIR and you care about the nesting between
+//!    item-like things.
+//!    - Example: Lifetime resolution, which wants to bring lifetimes declared on the
+//!      impl into scope while visiting the impl-items, and then back out again.
+//!    - How: Implement `intravisit::Visitor` and override the `NestedFilter` type to
+//!      `nested_filter::All` (and implement `nested_visit_map`). Walk your crate with
+//!      `tcx.hir().walk_toplevel_module(visitor)` invoked on `tcx.hir().krate()`.
+//!    - Pro: Visitor methods for any kind of HIR node, not just item-like things.
+//!    - Pro: Preserves nesting information
+//!    - Con: Does not integrate well into dependency tracking.
 //!
 //! If you have decided to use this visitor, here are some general
 //! notes on how to do so:
@@ -32,43 +65,12 @@
 //! example generator inference, and possibly also HIR borrowck.
 
 use crate::hir::*;
-use crate::itemlikevisit::{ItemLikeVisitor, ParItemLikeVisitor};
+use crate::itemlikevisit::ParItemLikeVisitor;
 use rustc_ast::walk_list;
 use rustc_ast::{Attribute, Label};
 use rustc_span::symbol::{Ident, Symbol};
 use rustc_span::Span;
 
-pub struct DeepVisitor<'v, V> {
-    visitor: &'v mut V,
-}
-
-impl<'v, V> DeepVisitor<'v, V> {
-    pub fn new(base: &'v mut V) -> Self {
-        DeepVisitor { visitor: base }
-    }
-}
-
-impl<'v, 'hir, V> ItemLikeVisitor<'hir> for DeepVisitor<'v, V>
-where
-    V: Visitor<'hir>,
-{
-    fn visit_item(&mut self, item: &'hir Item<'hir>) {
-        self.visitor.visit_item(item);
-    }
-
-    fn visit_trait_item(&mut self, trait_item: &'hir TraitItem<'hir>) {
-        self.visitor.visit_trait_item(trait_item);
-    }
-
-    fn visit_impl_item(&mut self, impl_item: &'hir ImplItem<'hir>) {
-        self.visitor.visit_impl_item(impl_item);
-    }
-
-    fn visit_foreign_item(&mut self, foreign_item: &'hir ForeignItem<'hir>) {
-        self.visitor.visit_foreign_item(foreign_item);
-    }
-}
-
 pub trait IntoVisitor<'hir> {
     type Visitor: Visitor<'hir>;
     fn into_visitor(&self) -> Self::Visitor;
@@ -315,16 +317,6 @@
         walk_body(self, b);
     }
 
-    /// When invoking `visit_all_item_likes()`, you need to supply an
-    /// item-like visitor. This method converts an "intra-visit"
-    /// visitor into an item-like visitor that walks the entire tree.
-    /// If you use this, you probably don't want to process the
-    /// contents of nested item-like things, since the outer loop will
-    /// visit them as well.
-    fn as_deep_visitor(&mut self) -> DeepVisitor<'_, Self> {
-        DeepVisitor::new(self)
-    }
-
     ///////////////////////////////////////////////////////////////////////////
 
     fn visit_id(&mut self, _hir_id: HirId) {
@@ -474,7 +466,7 @@
     fn visit_assoc_type_binding(&mut self, type_binding: &'v TypeBinding<'v>) {
         walk_assoc_type_binding(self, type_binding)
     }
-    fn visit_attribute(&mut self, _id: HirId, _attr: &'v Attribute) {}
+    fn visit_attribute(&mut self, _attr: &'v Attribute) {}
     fn visit_associated_item_kind(&mut self, kind: &'v AssocItemKind) {
         walk_associated_item_kind(self, kind);
     }
@@ -518,11 +510,11 @@
 pub fn walk_lifetime<'v, V: Visitor<'v>>(visitor: &mut V, lifetime: &'v Lifetime) {
     visitor.visit_id(lifetime.hir_id);
     match lifetime.name {
-        LifetimeName::Param(ParamName::Plain(ident)) => {
+        LifetimeName::Param(_, ParamName::Plain(ident)) => {
             visitor.visit_ident(ident);
         }
-        LifetimeName::Param(ParamName::Fresh(_))
-        | LifetimeName::Param(ParamName::Error)
+        LifetimeName::Param(_, ParamName::Fresh)
+        | LifetimeName::Param(_, ParamName::Error)
         | LifetimeName::Static
         | LifetimeName::Error
         | LifetimeName::Implicit
@@ -887,7 +879,7 @@
     visitor.visit_id(param.hir_id);
     match param.name {
         ParamName::Plain(ident) => visitor.visit_ident(ident),
-        ParamName::Error | ParamName::Fresh(_) => {}
+        ParamName::Error | ParamName::Fresh => {}
     }
     match param.kind {
         GenericParamKind::Lifetime { .. } => {}
@@ -1176,14 +1168,17 @@
             visitor.visit_expr(subexpression);
             walk_list!(visitor, visit_arm, arms);
         }
-        ExprKind::Closure(_, ref function_declaration, body, _fn_decl_span, _gen) => visitor
-            .visit_fn(
-                FnKind::Closure,
-                function_declaration,
-                body,
-                expression.span,
-                expression.hir_id,
-            ),
+        ExprKind::Closure {
+            bound_generic_params,
+            ref fn_decl,
+            body,
+            capture_clause: _,
+            fn_decl_span: _,
+            movability: _,
+        } => {
+            walk_list!(visitor, visit_generic_param, bound_generic_params);
+            visitor.visit_fn(FnKind::Closure, fn_decl, body, expression.span, expression.hir_id)
+        }
         ExprKind::Block(ref block, ref opt_label) => {
             walk_list!(visitor, visit_label, opt_label);
             visitor.visit_block(block);
@@ -1233,9 +1228,8 @@
     if let Some(ref g) = arm.guard {
         match g {
             Guard::If(ref e) => visitor.visit_expr(e),
-            Guard::IfLet(ref pat, ref e) => {
-                visitor.visit_pat(pat);
-                visitor.visit_expr(e);
+            Guard::IfLet(ref l) => {
+                visitor.visit_let_expr(l);
             }
         }
     }
diff --git a/compiler/rustc_hir/src/itemlikevisit.rs b/compiler/rustc_hir/src/itemlikevisit.rs
index b2c6ca1..a490268 100644
--- a/compiler/rustc_hir/src/itemlikevisit.rs
+++ b/compiler/rustc_hir/src/itemlikevisit.rs
@@ -1,55 +1,5 @@
 use super::{ForeignItem, ImplItem, Item, TraitItem};
 
-/// The "item-like visitor" defines only the top-level methods
-/// that can be invoked by `Crate::visit_all_item_likes()`. Whether
-/// this trait is the right one to implement will depend on the
-/// overall pattern you need. Here are the three available patterns,
-/// in roughly the order of desirability:
-///
-/// 1. **Shallow visit**: Get a simple callback for every item (or item-like thing) in the HIR.
-///    - Example: find all items with a `#[foo]` attribute on them.
-///    - How: Implement `ItemLikeVisitor` and call `tcx.hir().visit_all_item_likes()`.
-///    - Pro: Efficient; just walks the lists of item-like things, not the nodes themselves.
-///    - Con: Don't get information about nesting
-///    - Con: Don't have methods for specific bits of HIR, like "on
-///      every expr, do this".
-/// 2. **Deep visit**: Want to scan for specific kinds of HIR nodes within
-///    an item, but don't care about how item-like things are nested
-///    within one another.
-///    - Example: Examine each expression to look for its type and do some check or other.
-///    - How: Implement `intravisit::Visitor` and override the `NestedFilter` type to
-///      `nested_filter::OnlyBodies` (and implement `nested_visit_map`), and use
-///      `tcx.hir().visit_all_item_likes(&mut visitor.as_deep_visitor())`. Within your
-///      `intravisit::Visitor` impl, implement methods like `visit_expr()` (don't forget to invoke
-///      `intravisit::walk_expr()` to keep walking the subparts).
-///    - Pro: Visitor methods for any kind of HIR node, not just item-like things.
-///    - Pro: Integrates well into dependency tracking.
-///    - Con: Don't get information about nesting between items
-/// 3. **Nested visit**: Want to visit the whole HIR and you care about the nesting between
-///    item-like things.
-///    - Example: Lifetime resolution, which wants to bring lifetimes declared on the
-///      impl into scope while visiting the impl-items, and then back out again.
-///    - How: Implement `intravisit::Visitor` and override the `NestedFilter` type to
-///      `nested_filter::All` (and implement `nested_visit_map`). Walk your crate with
-///      `tcx.hir().walk_toplevel_module(visitor)` invoked on `tcx.hir().krate()`.
-///    - Pro: Visitor methods for any kind of HIR node, not just item-like things.
-///    - Pro: Preserves nesting information
-///    - Con: Does not integrate well into dependency tracking.
-///
-/// Note: the methods of `ItemLikeVisitor` intentionally have no
-/// defaults, so that as we expand the list of item-like things, we
-/// revisit the various visitors to see if they need to change. This
-/// is harder to do with `intravisit::Visitor`, so when you add a new
-/// `visit_nested_foo()` method, it is recommended that you search for
-/// existing `fn visit_nested` methods to see where changes are
-/// needed.
-pub trait ItemLikeVisitor<'hir> {
-    fn visit_item(&mut self, item: &'hir Item<'hir>);
-    fn visit_trait_item(&mut self, trait_item: &'hir TraitItem<'hir>);
-    fn visit_impl_item(&mut self, impl_item: &'hir ImplItem<'hir>);
-    fn visit_foreign_item(&mut self, foreign_item: &'hir ForeignItem<'hir>);
-}
-
 /// A parallel variant of `ItemLikeVisitor`.
 pub trait ParItemLikeVisitor<'hir> {
     fn visit_item(&self, item: &'hir Item<'hir>);
diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs
index 9e5d781..b0bfac8 100644
--- a/compiler/rustc_hir/src/lang_items.rs
+++ b/compiler/rustc_hir/src/lang_items.rs
@@ -17,7 +17,7 @@
 use rustc_span::symbol::{kw, sym, Symbol};
 use rustc_span::Span;
 
-use std::lazy::SyncLazy;
+use std::sync::LazyLock;
 
 pub enum LangItemGroup {
     Op,
@@ -134,7 +134,7 @@
         }
 
         /// A mapping from the name of the lang item to its order and the form it must be of.
-        pub static ITEM_REFS: SyncLazy<FxHashMap<Symbol, (usize, Target)>> = SyncLazy::new(|| {
+        pub static ITEM_REFS: LazyLock<FxHashMap<Symbol, (usize, Target)>> = LazyLock::new(|| {
             let mut item_refs = FxHashMap::default();
             $( item_refs.insert($module::$name, (LangItem::$variant as usize, $target)); )*
             item_refs
diff --git a/compiler/rustc_hir/src/lib.rs b/compiler/rustc_hir/src/lib.rs
index d56230e..d845c43 100644
--- a/compiler/rustc_hir/src/lib.rs
+++ b/compiler/rustc_hir/src/lib.rs
@@ -3,8 +3,8 @@
 //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/hir.html
 
 #![feature(associated_type_defaults)]
+#![feature(closure_track_caller)]
 #![feature(const_btree_new)]
-#![feature(crate_visibility_modifier)]
 #![feature(let_else)]
 #![feature(once_cell)]
 #![feature(min_specialization)]
diff --git a/compiler/rustc_hir/src/weak_lang_items.rs b/compiler/rustc_hir/src/weak_lang_items.rs
index 7874820..dad2272 100644
--- a/compiler/rustc_hir/src/weak_lang_items.rs
+++ b/compiler/rustc_hir/src/weak_lang_items.rs
@@ -7,12 +7,12 @@
 use rustc_data_structures::stable_map::StableMap;
 use rustc_span::symbol::{sym, Symbol};
 
-use std::lazy::SyncLazy;
+use std::sync::LazyLock;
 
 macro_rules! weak_lang_items {
     ($($name:ident, $item:ident, $sym:ident;)*) => (
 
-pub static WEAK_ITEMS_REFS: SyncLazy<StableMap<Symbol, LangItem>> = SyncLazy::new(|| {
+pub static WEAK_ITEMS_REFS: LazyLock<StableMap<Symbol, LangItem>> = LazyLock::new(|| {
     let mut map = StableMap::default();
     $(map.insert(sym::$name, LangItem::$item);)*
     map
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index 7af9622..7bf91df 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -85,6 +85,7 @@
             Node::Stmt(a) => self.print_stmt(&a),
             Node::PathSegment(a) => self.print_path_segment(&a),
             Node::Ty(a) => self.print_type(&a),
+            Node::TypeBinding(a) => self.print_type_binding(&a),
             Node::TraitRef(a) => self.print_trait_ref(&a),
             Node::Binding(a) | Node::Pat(a) => self.print_pat(&a),
             Node::Arm(a) => self.print_arm(&a),
@@ -1077,7 +1078,9 @@
     // parses as the erroneous construct `if (return {})`, not `if (return) {}`.
     fn cond_needs_par(expr: &hir::Expr<'_>) -> bool {
         match expr.kind {
-            hir::ExprKind::Break(..) | hir::ExprKind::Closure(..) | hir::ExprKind::Ret(..) => true,
+            hir::ExprKind::Break(..) | hir::ExprKind::Closure { .. } | hir::ExprKind::Ret(..) => {
+                true
+            }
             _ => contains_exterior_struct_lit(expr),
         }
     }
@@ -1454,10 +1457,18 @@
                 }
                 self.bclose(expr.span);
             }
-            hir::ExprKind::Closure(capture_clause, ref decl, body, _fn_decl_span, _gen) => {
+            hir::ExprKind::Closure {
+                capture_clause,
+                bound_generic_params,
+                ref fn_decl,
+                body,
+                fn_decl_span: _,
+                movability: _,
+            } => {
+                self.print_formal_generic_params(bound_generic_params);
                 self.print_capture_clause(capture_clause);
 
-                self.print_closure_params(&decl, body);
+                self.print_closure_params(&fn_decl, body);
                 self.space();
 
                 // This is a bare expression.
@@ -1703,21 +1714,7 @@
 
             for binding in generic_args.bindings.iter() {
                 start_or_comma(self);
-                self.print_ident(binding.ident);
-                self.print_generic_args(binding.gen_args, false, false);
-                self.space();
-                match generic_args.bindings[0].kind {
-                    hir::TypeBindingKind::Equality { ref term } => {
-                        self.word_space("=");
-                        match term {
-                            Term::Ty(ref ty) => self.print_type(ty),
-                            Term::Const(ref c) => self.print_anon_const(c),
-                        }
-                    }
-                    hir::TypeBindingKind::Constraint { bounds } => {
-                        self.print_bounds(":", bounds);
-                    }
-                }
+                self.print_type_binding(binding);
             }
 
             if !empty.get() {
@@ -1726,6 +1723,24 @@
         }
     }
 
+    pub fn print_type_binding(&mut self, binding: &hir::TypeBinding<'_>) {
+        self.print_ident(binding.ident);
+        self.print_generic_args(binding.gen_args, false, false);
+        self.space();
+        match binding.kind {
+            hir::TypeBindingKind::Equality { ref term } => {
+                self.word_space("=");
+                match term {
+                    Term::Ty(ref ty) => self.print_type(ty),
+                    Term::Const(ref c) => self.print_anon_const(c),
+                }
+            }
+            hir::TypeBindingKind::Constraint { bounds } => {
+                self.print_bounds(":", bounds);
+            }
+        }
+    }
+
     pub fn print_pat(&mut self, pat: &hir::Pat<'_>) {
         self.maybe_print_comment(pat.span.lo());
         self.ann.pre(self, AnnNode::Pat(pat));
@@ -1915,14 +1930,9 @@
                     self.print_expr(&e);
                     self.space();
                 }
-                hir::Guard::IfLet(pat, e) => {
+                hir::Guard::IfLet(hir::Let { pat, ty, init, .. }) => {
                     self.word_nbsp("if");
-                    self.word_nbsp("let");
-                    self.print_pat(&pat);
-                    self.space();
-                    self.word_space("=");
-                    self.print_expr(&e);
-                    self.space();
+                    self.print_let(pat, *ty, init);
                 }
             }
         }
diff --git a/compiler/rustc_incremental/src/assert_dep_graph.rs b/compiler/rustc_incremental/src/assert_dep_graph.rs
index f69ae8e..a89b9ea 100644
--- a/compiler/rustc_incremental/src/assert_dep_graph.rs
+++ b/compiler/rustc_incremental/src/assert_dep_graph.rs
@@ -75,7 +75,7 @@
             let mut visitor =
                 IfThisChanged { tcx, if_this_changed: vec![], then_this_would_need: vec![] };
             visitor.process_attrs(hir::CRATE_HIR_ID);
-            tcx.hir().visit_all_item_likes(&mut visitor.as_deep_visitor());
+            tcx.hir().deep_visit_all_item_likes(&mut visitor);
             (visitor.if_this_changed, visitor.then_this_would_need)
         };
 
diff --git a/compiler/rustc_incremental/src/lib.rs b/compiler/rustc_incremental/src/lib.rs
index 0171134..1e88e80 100644
--- a/compiler/rustc_incremental/src/lib.rs
+++ b/compiler/rustc_incremental/src/lib.rs
@@ -3,7 +3,6 @@
 #![deny(missing_docs)]
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![feature(let_else)]
-#![feature(nll)]
 #![recursion_limit = "256"]
 #![allow(rustc::potential_query_instability)]
 
diff --git a/compiler/rustc_incremental/src/persist/dirty_clean.rs b/compiler/rustc_incremental/src/persist/dirty_clean.rs
index 424164d..9409735 100644
--- a/compiler/rustc_incremental/src/persist/dirty_clean.rs
+++ b/compiler/rustc_incremental/src/persist/dirty_clean.rs
@@ -21,7 +21,6 @@
 
 use rustc_ast::{self as ast, Attribute, NestedMetaItem};
 use rustc_data_structures::fx::FxHashSet;
-use rustc_hir as hir;
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::intravisit;
 use rustc_hir::Node as HirNode;
@@ -473,7 +472,7 @@
         self.tcx.hir()
     }
 
-    fn visit_attribute(&mut self, _: hir::HirId, attr: &'tcx Attribute) {
+    fn visit_attribute(&mut self, attr: &'tcx Attribute) {
         if self.is_active_attr(attr) {
             self.found_attrs.push(attr);
         }
diff --git a/compiler/rustc_incremental/src/persist/file_format.rs b/compiler/rustc_incremental/src/persist/file_format.rs
index 68180a2..2dbd4b6 100644
--- a/compiler/rustc_incremental/src/persist/file_format.rs
+++ b/compiler/rustc_incremental/src/persist/file_format.rs
@@ -30,22 +30,20 @@
 /// the Git commit hash.
 const RUSTC_VERSION: Option<&str> = option_env!("CFG_VERSION");
 
-pub(crate) fn write_file_header(stream: &mut FileEncoder, nightly_build: bool) -> FileEncodeResult {
-    stream.emit_raw_bytes(FILE_MAGIC)?;
-    stream.emit_raw_bytes(&[
-        (HEADER_FORMAT_VERSION >> 0) as u8,
-        (HEADER_FORMAT_VERSION >> 8) as u8,
-    ])?;
+pub(crate) fn write_file_header(stream: &mut FileEncoder, nightly_build: bool) {
+    stream.emit_raw_bytes(FILE_MAGIC);
+    stream
+        .emit_raw_bytes(&[(HEADER_FORMAT_VERSION >> 0) as u8, (HEADER_FORMAT_VERSION >> 8) as u8]);
 
     let rustc_version = rustc_version(nightly_build);
     assert_eq!(rustc_version.len(), (rustc_version.len() as u8) as usize);
-    stream.emit_raw_bytes(&[rustc_version.len() as u8])?;
-    stream.emit_raw_bytes(rustc_version.as_bytes())
+    stream.emit_raw_bytes(&[rustc_version.len() as u8]);
+    stream.emit_raw_bytes(rustc_version.as_bytes());
 }
 
 pub(crate) fn save_in<F>(sess: &Session, path_buf: PathBuf, name: &str, encode: F)
 where
-    F: FnOnce(&mut FileEncoder) -> FileEncodeResult,
+    F: FnOnce(FileEncoder) -> FileEncodeResult,
 {
     debug!("save: storing data in {}", path_buf.display());
 
@@ -80,28 +78,21 @@
         }
     };
 
-    if let Err(err) = write_file_header(&mut encoder, sess.is_nightly_build()) {
-        sess.err(&format!("failed to write {} header to `{}`: {}", name, path_buf.display(), err));
-        return;
+    write_file_header(&mut encoder, sess.is_nightly_build());
+
+    match encode(encoder) {
+        Ok(position) => {
+            sess.prof.artifact_size(
+                &name.replace(' ', "_"),
+                path_buf.file_name().unwrap().to_string_lossy(),
+                position as u64,
+            );
+            debug!("save: data written to disk successfully");
+        }
+        Err(err) => {
+            sess.err(&format!("failed to write {} to `{}`: {}", name, path_buf.display(), err));
+        }
     }
-
-    if let Err(err) = encode(&mut encoder) {
-        sess.err(&format!("failed to write {} to `{}`: {}", name, path_buf.display(), err));
-        return;
-    }
-
-    if let Err(err) = encoder.flush() {
-        sess.err(&format!("failed to flush {} to `{}`: {}", name, path_buf.display(), err));
-        return;
-    }
-
-    sess.prof.artifact_size(
-        &name.replace(' ', "_"),
-        path_buf.file_name().unwrap().to_string_lossy(),
-        encoder.position() as u64,
-    );
-
-    debug!("save: data written to disk successfully");
 }
 
 /// Reads the contents of a file with a file header as defined in this module.
diff --git a/compiler/rustc_incremental/src/persist/load.rs b/compiler/rustc_incremental/src/persist/load.rs
index 908a936..9c325fa 100644
--- a/compiler/rustc_incremental/src/persist/load.rs
+++ b/compiler/rustc_incremental/src/persist/load.rs
@@ -4,7 +4,7 @@
 use rustc_data_structures::memmap::Mmap;
 use rustc_middle::dep_graph::{SerializedDepGraph, WorkProduct, WorkProductId};
 use rustc_middle::ty::OnDiskCache;
-use rustc_serialize::opaque::Decoder;
+use rustc_serialize::opaque::MemDecoder;
 use rustc_serialize::Decodable;
 use rustc_session::config::IncrementalStateAssertion;
 use rustc_session::Session;
@@ -156,24 +156,22 @@
 
         if let LoadResult::Ok { data: (work_products_data, start_pos) } = load_result {
             // Decode the list of work_products
-            let mut work_product_decoder = Decoder::new(&work_products_data[..], start_pos);
+            let mut work_product_decoder = MemDecoder::new(&work_products_data[..], start_pos);
             let work_products: Vec<SerializedWorkProduct> =
                 Decodable::decode(&mut work_product_decoder);
 
             for swp in work_products {
                 let mut all_files_exist = true;
-                if let Some(ref file_name) = swp.work_product.saved_file {
-                    let path = in_incr_comp_dir_sess(sess, file_name);
-                    if !path.exists() {
-                        all_files_exist = false;
+                let path = in_incr_comp_dir_sess(sess, &swp.work_product.saved_file);
+                if !path.exists() {
+                    all_files_exist = false;
 
-                        if sess.opts.debugging_opts.incremental_info {
-                            eprintln!(
-                                "incremental: could not find file for work \
+                    if sess.opts.debugging_opts.incremental_info {
+                        eprintln!(
+                            "incremental: could not find file for work \
                                     product: {}",
-                                path.display()
-                            );
-                        }
+                            path.display()
+                        );
                     }
                 }
 
@@ -195,7 +193,7 @@
             LoadResult::DataOutOfDate => LoadResult::DataOutOfDate,
             LoadResult::Error { message } => LoadResult::Error { message },
             LoadResult::Ok { data: (bytes, start_pos) } => {
-                let mut decoder = Decoder::new(&bytes, start_pos);
+                let mut decoder = MemDecoder::new(&bytes, start_pos);
                 let prev_commandline_args_hash = u64::decode(&mut decoder);
 
                 if prev_commandline_args_hash != expected_hash {
diff --git a/compiler/rustc_incremental/src/persist/save.rs b/compiler/rustc_incremental/src/persist/save.rs
index 20ffde9..79836d6 100644
--- a/compiler/rustc_incremental/src/persist/save.rs
+++ b/compiler/rustc_incremental/src/persist/save.rs
@@ -96,8 +96,9 @@
     debug!("save_work_product_index()");
     dep_graph.assert_ignored();
     let path = work_products_path(sess);
-    file_format::save_in(sess, path, "work product index", |e| {
-        encode_work_product_index(&new_work_products, e)
+    file_format::save_in(sess, path, "work product index", |mut e| {
+        encode_work_product_index(&new_work_products, &mut e);
+        e.finish()
     });
 
     // We also need to clean out old work-products, as not all of them are
@@ -107,11 +108,7 @@
     for (id, wp) in previous_work_products.iter() {
         if !new_work_products.contains_key(id) {
             work_product::delete_workproduct_files(sess, wp);
-            debug_assert!(
-                wp.saved_file.as_ref().map_or(true, |file_name| {
-                    !in_incr_comp_dir_sess(sess, &file_name).exists()
-                })
-            );
+            debug_assert!(!in_incr_comp_dir_sess(sess, &wp.saved_file).exists());
         }
     }
 
@@ -119,8 +116,7 @@
     debug_assert!({
         new_work_products
             .iter()
-            .flat_map(|(_, wp)| wp.saved_file.iter())
-            .map(|name| in_incr_comp_dir_sess(sess, name))
+            .map(|(_, wp)| in_incr_comp_dir_sess(sess, &wp.saved_file))
             .all(|path| path.exists())
     });
 }
@@ -128,7 +124,7 @@
 fn encode_work_product_index(
     work_products: &FxHashMap<WorkProductId, WorkProduct>,
     encoder: &mut FileEncoder,
-) -> FileEncodeResult {
+) {
     let serialized_products: Vec<_> = work_products
         .iter()
         .map(|(id, work_product)| SerializedWorkProduct {
@@ -140,7 +136,7 @@
     serialized_products.encode(encoder)
 }
 
-fn encode_query_cache(tcx: TyCtxt<'_>, encoder: &mut FileEncoder) -> FileEncodeResult {
+fn encode_query_cache(tcx: TyCtxt<'_>, encoder: FileEncoder) -> FileEncodeResult {
     tcx.sess.time("incr_comp_serialize_result_cache", || tcx.serialize_query_result_cache(encoder))
 }
 
@@ -175,24 +171,10 @@
         }
     };
 
-    if let Err(err) = file_format::write_file_header(&mut encoder, sess.is_nightly_build()) {
-        sess.err(&format!(
-            "failed to write dependency graph header to `{}`: {}",
-            path_buf.display(),
-            err
-        ));
-        return None;
-    }
+    file_format::write_file_header(&mut encoder, sess.is_nightly_build());
 
     // First encode the commandline arguments hash
-    if let Err(err) = sess.opts.dep_tracking_hash(false).encode(&mut encoder) {
-        sess.err(&format!(
-            "failed to write dependency graph hash `{}`: {}",
-            path_buf.display(),
-            err
-        ));
-        return None;
-    }
+    sess.opts.dep_tracking_hash(false).encode(&mut encoder);
 
     Some(DepGraph::new(
         &sess.prof,
diff --git a/compiler/rustc_incremental/src/persist/work_product.rs b/compiler/rustc_incremental/src/persist/work_product.rs
index 85b44ed..4789c0f 100644
--- a/compiler/rustc_incremental/src/persist/work_product.rs
+++ b/compiler/rustc_incremental/src/persist/work_product.rs
@@ -7,34 +7,30 @@
 use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
 use rustc_session::Session;
 use std::fs as std_fs;
-use std::path::PathBuf;
+use std::path::Path;
 
 /// Copies a CGU work product to the incremental compilation directory, so next compilation can find and reuse it.
 pub fn copy_cgu_workproduct_to_incr_comp_cache_dir(
     sess: &Session,
     cgu_name: &str,
-    path: &Option<PathBuf>,
+    path: &Path,
 ) -> Option<(WorkProductId, WorkProduct)> {
     debug!("copy_cgu_workproduct_to_incr_comp_cache_dir({:?},{:?})", cgu_name, path);
     sess.opts.incremental.as_ref()?;
 
-    let saved_file = if let Some(path) = path {
-        let file_name = format!("{}.o", cgu_name);
-        let path_in_incr_dir = in_incr_comp_dir_sess(sess, &file_name);
-        match link_or_copy(path, &path_in_incr_dir) {
-            Ok(_) => Some(file_name),
-            Err(err) => {
-                sess.warn(&format!(
-                    "error copying object file `{}` to incremental directory as `{}`: {}",
-                    path.display(),
-                    path_in_incr_dir.display(),
-                    err
-                ));
-                return None;
-            }
+    let file_name = format!("{}.o", cgu_name);
+    let path_in_incr_dir = in_incr_comp_dir_sess(sess, &file_name);
+    let saved_file = match link_or_copy(path, &path_in_incr_dir) {
+        Ok(_) => file_name,
+        Err(err) => {
+            sess.warn(&format!(
+                "error copying object file `{}` to incremental directory as `{}`: {}",
+                path.display(),
+                path_in_incr_dir.display(),
+                err
+            ));
+            return None;
         }
-    } else {
-        None
     };
 
     let work_product = WorkProduct { cgu_name: cgu_name.to_string(), saved_file };
@@ -45,17 +41,15 @@
 
 /// Removes files for a given work product.
 pub fn delete_workproduct_files(sess: &Session, work_product: &WorkProduct) {
-    if let Some(ref file_name) = work_product.saved_file {
-        let path = in_incr_comp_dir_sess(sess, file_name);
-        match std_fs::remove_file(&path) {
-            Ok(()) => {}
-            Err(err) => {
-                sess.warn(&format!(
-                    "file-system error deleting outdated file `{}`: {}",
-                    path.display(),
-                    err
-                ));
-            }
+    let path = in_incr_comp_dir_sess(sess, &work_product.saved_file);
+    match std_fs::remove_file(&path) {
+        Ok(()) => {}
+        Err(err) => {
+            sess.warn(&format!(
+                "file-system error deleting outdated file `{}`: {}",
+                path.display(),
+                err
+            ));
         }
     }
 }
diff --git a/compiler/rustc_index/src/bit_set.rs b/compiler/rustc_index/src/bit_set.rs
index 059755a..976874c 100644
--- a/compiler/rustc_index/src/bit_set.rs
+++ b/compiler/rustc_index/src/bit_set.rs
@@ -340,6 +340,12 @@
     }
 }
 
+impl<T: Idx> From<GrowableBitSet<T>> for BitSet<T> {
+    fn from(bit_set: GrowableBitSet<T>) -> Self {
+        bit_set.bit_set
+    }
+}
+
 /// A fixed-size bitset type with a partially dense, partially sparse
 /// representation. The bitset is broken into chunks, and chunks that are all
 /// zeros or all ones are represented and handled very efficiently.
@@ -681,6 +687,48 @@
     }
 }
 
+impl<T: Idx> BitRelations<ChunkedBitSet<T>> for BitSet<T> {
+    fn union(&mut self, other: &ChunkedBitSet<T>) -> bool {
+        sequential_update(|elem| self.insert(elem), other.iter())
+    }
+
+    fn subtract(&mut self, _other: &ChunkedBitSet<T>) -> bool {
+        unimplemented!("implement if/when necessary");
+    }
+
+    fn intersect(&mut self, other: &ChunkedBitSet<T>) -> bool {
+        assert_eq!(self.domain_size(), other.domain_size);
+        let mut changed = false;
+        for (i, chunk) in other.chunks.iter().enumerate() {
+            let mut words = &mut self.words[i * CHUNK_WORDS..];
+            if words.len() > CHUNK_WORDS {
+                words = &mut words[..CHUNK_WORDS];
+            }
+            match chunk {
+                Chunk::Zeros(..) => {
+                    for word in words {
+                        if *word != 0 {
+                            changed = true;
+                            *word = 0;
+                        }
+                    }
+                }
+                Chunk::Ones(..) => (),
+                Chunk::Mixed(_, _, data) => {
+                    for (i, word) in words.iter_mut().enumerate() {
+                        let new_val = *word & data[i];
+                        if new_val != *word {
+                            changed = true;
+                            *word = new_val;
+                        }
+                    }
+                }
+            }
+        }
+        changed
+    }
+}
+
 impl<T> Clone for ChunkedBitSet<T> {
     fn clone(&self) -> Self {
         ChunkedBitSet {
@@ -743,6 +791,41 @@
         }
         None
     }
+
+    fn fold<B, F>(mut self, mut init: B, mut f: F) -> B
+    where
+        F: FnMut(B, Self::Item) -> B,
+    {
+        // If `next` has already been called, we may not be at the start of a chunk, so we first
+        // advance the iterator to the start of the next chunk, before proceeding in chunk sized
+        // steps.
+        while self.index % CHUNK_BITS != 0 {
+            let Some(item) = self.next() else {
+                return init
+            };
+            init = f(init, item);
+        }
+        let start_chunk = self.index / CHUNK_BITS;
+        let chunks = &self.bitset.chunks[start_chunk..];
+        for (i, chunk) in chunks.iter().enumerate() {
+            let base = (start_chunk + i) * CHUNK_BITS;
+            match chunk {
+                Chunk::Zeros(_) => (),
+                Chunk::Ones(limit) => {
+                    for j in 0..(*limit as usize) {
+                        init = f(init, T::new(base + j));
+                    }
+                }
+                Chunk::Mixed(_, _, words) => {
+                    init = BitIter::new(&**words).fold(init, |val, mut item: T| {
+                        item.increment_by(base);
+                        f(val, item)
+                    });
+                }
+            }
+        }
+        init
+    }
 }
 
 impl Chunk {
@@ -799,11 +882,7 @@
     mut self_update: impl FnMut(T) -> bool,
     it: impl Iterator<Item = T>,
 ) -> bool {
-    let mut changed = false;
-    for elem in it {
-        changed |= self_update(elem);
-    }
-    changed
+    it.fold(false, |changed, elem| self_update(elem) | changed)
 }
 
 // Optimization of intersection for SparseBitSet that's generic
@@ -1469,6 +1548,12 @@
     }
 }
 
+impl<T: Idx> From<BitSet<T>> for GrowableBitSet<T> {
+    fn from(bit_set: BitSet<T>) -> Self {
+        Self { bit_set }
+    }
+}
+
 /// A fixed-size 2D bit matrix type with a dense representation.
 ///
 /// `R` and `C` are index types used to identify rows and columns respectively;
diff --git a/compiler/rustc_index/src/bit_set/tests.rs b/compiler/rustc_index/src/bit_set/tests.rs
index cfc891e..a58133e 100644
--- a/compiler/rustc_index/src/bit_set/tests.rs
+++ b/compiler/rustc_index/src/bit_set/tests.rs
@@ -342,38 +342,82 @@
     b10000b.assert_valid();
 }
 
+fn with_elements_chunked(elements: &[usize], domain_size: usize) -> ChunkedBitSet<usize> {
+    let mut s = ChunkedBitSet::new_empty(domain_size);
+    for &e in elements {
+        assert!(s.insert(e));
+    }
+    s
+}
+
+fn with_elements_standard(elements: &[usize], domain_size: usize) -> BitSet<usize> {
+    let mut s = BitSet::new_empty(domain_size);
+    for &e in elements {
+        assert!(s.insert(e));
+    }
+    s
+}
+
+#[test]
+fn chunked_bitset_into_bitset_operations() {
+    let a = vec![1, 5, 7, 11, 15, 2000, 3000];
+    let b = vec![3, 4, 11, 3000, 4000];
+    let aub = vec![1, 3, 4, 5, 7, 11, 15, 2000, 3000, 4000];
+    let aib = vec![11, 3000];
+
+    let b = with_elements_chunked(&b, 9876);
+
+    let mut union = with_elements_standard(&a, 9876);
+    assert!(union.union(&b));
+    assert!(!union.union(&b));
+    assert!(union.iter().eq(aub.iter().copied()));
+
+    let mut intersection = with_elements_standard(&a, 9876);
+    assert!(intersection.intersect(&b));
+    assert!(!intersection.intersect(&b));
+    assert!(intersection.iter().eq(aib.iter().copied()));
+}
+
 #[test]
 fn chunked_bitset_iter() {
-    fn with_elements(elements: &[usize], domain_size: usize) -> ChunkedBitSet<usize> {
-        let mut s = ChunkedBitSet::new_empty(domain_size);
-        for &e in elements {
-            s.insert(e);
+    fn check_iter(bit: &ChunkedBitSet<usize>, vec: &Vec<usize>) {
+        // Test collecting via both `.next()` and `.fold()` calls, to make sure both are correct
+        let mut collect_next = Vec::new();
+        let mut bit_iter = bit.iter();
+        while let Some(item) = bit_iter.next() {
+            collect_next.push(item);
         }
-        s
+        assert_eq!(vec, &collect_next);
+
+        let collect_fold = bit.iter().fold(Vec::new(), |mut v, item| {
+            v.push(item);
+            v
+        });
+        assert_eq!(vec, &collect_fold);
     }
 
     // Empty
     let vec: Vec<usize> = Vec::new();
-    let bit = with_elements(&vec, 9000);
-    assert_eq!(vec, bit.iter().collect::<Vec<_>>());
+    let bit = with_elements_chunked(&vec, 9000);
+    check_iter(&bit, &vec);
 
     // Filled
     let n = 10000;
     let vec: Vec<usize> = (0..n).collect();
-    let bit = with_elements(&vec, n);
-    assert_eq!(vec, bit.iter().collect::<Vec<_>>());
+    let bit = with_elements_chunked(&vec, n);
+    check_iter(&bit, &vec);
 
     // Filled with trailing zeros
     let n = 10000;
     let vec: Vec<usize> = (0..n).collect();
-    let bit = with_elements(&vec, 2 * n);
-    assert_eq!(vec, bit.iter().collect::<Vec<_>>());
+    let bit = with_elements_chunked(&vec, 2 * n);
+    check_iter(&bit, &vec);
 
     // Mixed
     let n = 12345;
     let vec: Vec<usize> = vec![0, 1, 2, 2010, 2047, 2099, 6000, 6002, 6004];
-    let bit = with_elements(&vec, n);
-    assert_eq!(vec, bit.iter().collect::<Vec<_>>());
+    let bit = with_elements_chunked(&vec, n);
+    check_iter(&bit, &vec);
 }
 
 #[test]
diff --git a/compiler/rustc_index/src/interval.rs b/compiler/rustc_index/src/interval.rs
index ed50493..3592fb3 100644
--- a/compiler/rustc_index/src/interval.rs
+++ b/compiler/rustc_index/src/interval.rs
@@ -1,7 +1,7 @@
 use std::iter::Step;
 use std::marker::PhantomData;
-use std::ops::Bound;
 use std::ops::RangeBounds;
+use std::ops::{Bound, Range};
 
 use crate::vec::Idx;
 use crate::vec::IndexVec;
@@ -11,6 +11,10 @@
 mod tests;
 
 /// Stores a set of intervals on the indices.
+///
+/// The elements in `map` are sorted and non-adjacent, which means
+/// the second value of the previous element is *greater* than the
+/// first value of the following element.
 #[derive(Debug, Clone)]
 pub struct IntervalSet<I> {
     // Start, end
@@ -70,7 +74,7 @@
     /// Returns true if we increased the number of elements present.
     pub fn insert_range(&mut self, range: impl RangeBounds<I> + Clone) -> bool {
         let start = inclusive_start(range.clone());
-        let Some(mut end) = inclusive_end(self.domain, range) else {
+        let Some(end) = inclusive_end(self.domain, range) else {
             // empty range
             return false;
         };
@@ -78,60 +82,65 @@
             return false;
         }
 
-        loop {
-            // This condition looks a bit weird, but actually makes sense.
-            //
-            // if r.0 == end + 1, then we're actually adjacent, so we want to
-            // continue to the next range. We're looking here for the first
-            // range which starts *non-adjacently* to our end.
-            let next = self.map.partition_point(|r| r.0 <= end + 1);
-            if let Some(last) = next.checked_sub(1) {
-                let (prev_start, prev_end) = &mut self.map[last];
-                if *prev_end + 1 >= start {
-                    // If the start for the inserted range is adjacent to the
-                    // end of the previous, we can extend the previous range.
-                    if start < *prev_start {
-                        // Our range starts before the one we found. We'll need
-                        // to *remove* it, and then try again.
-                        //
-                        // FIXME: This is not so efficient; we may need to
-                        // recurse a bunch of times here. Instead, it's probably
-                        // better to do something like drain_filter(...) on the
-                        // map to be able to delete or modify all the ranges in
-                        // start..=end and then potentially re-insert a new
-                        // range.
-                        end = std::cmp::max(end, *prev_end);
-                        self.map.remove(last);
-                    } else {
-                        // We overlap with the previous range, increase it to
-                        // include us.
-                        //
-                        // Make sure we're actually going to *increase* it though --
-                        // it may be that end is just inside the previously existing
-                        // set.
-                        return if end > *prev_end {
-                            *prev_end = end;
-                            true
-                        } else {
-                            false
-                        };
+        // This condition looks a bit weird, but actually makes sense.
+        //
+        // if r.0 == end + 1, then we're actually adjacent, so we want to
+        // continue to the next range. We're looking here for the first
+        // range which starts *non-adjacently* to our end.
+        let next = self.map.partition_point(|r| r.0 <= end + 1);
+        let result = if let Some(right) = next.checked_sub(1) {
+            let (prev_start, prev_end) = self.map[right];
+            if prev_end + 1 >= start {
+                // If the start for the inserted range is adjacent to the
+                // end of the previous, we can extend the previous range.
+                if start < prev_start {
+                    // The first range which ends *non-adjacently* to our start.
+                    // And we can ensure that left <= right.
+                    let left = self.map.partition_point(|l| l.1 + 1 < start);
+                    let min = std::cmp::min(self.map[left].0, start);
+                    let max = std::cmp::max(prev_end, end);
+                    self.map[right] = (min, max);
+                    if left != right {
+                        self.map.drain(left..right);
                     }
+                    true
                 } else {
-                    // Otherwise, we don't overlap, so just insert
-                    self.map.insert(last + 1, (start, end));
-                    return true;
+                    // We overlap with the previous range, increase it to
+                    // include us.
+                    //
+                    // Make sure we're actually going to *increase* it though --
+                    // it may be that end is just inside the previously existing
+                    // set.
+                    if end > prev_end {
+                        self.map[right].1 = end;
+                        true
+                    } else {
+                        false
+                    }
                 }
             } else {
-                if self.map.is_empty() {
-                    // Quite common in practice, and expensive to call memcpy
-                    // with length zero.
-                    self.map.push((start, end));
-                } else {
-                    self.map.insert(next, (start, end));
-                }
-                return true;
+                // Otherwise, we don't overlap, so just insert
+                self.map.insert(right + 1, (start, end));
+                true
             }
-        }
+        } else {
+            if self.map.is_empty() {
+                // Quite common in practice, and expensive to call memcpy
+                // with length zero.
+                self.map.push((start, end));
+            } else {
+                self.map.insert(next, (start, end));
+            }
+            true
+        };
+        debug_assert!(
+            self.check_invariants(),
+            "wrong intervals after insert {:?}..={:?} to {:?}",
+            start,
+            end,
+            self
+        );
+        result
     }
 
     pub fn contains(&self, needle: I) -> bool {
@@ -148,9 +157,26 @@
     where
         I: Step,
     {
-        // FIXME: Performance here is probably not great. We will be doing a lot
-        // of pointless tree traversals.
-        other.iter().all(|elem| self.contains(elem))
+        let mut sup_iter = self.iter_intervals();
+        let mut current = None;
+        let contains = |sup: Range<I>, sub: Range<I>, current: &mut Option<Range<I>>| {
+            if sup.end < sub.start {
+                // if `sup.end == sub.start`, the next sup doesn't contain `sub.start`
+                None // continue to the next sup
+            } else if sup.end >= sub.end && sup.start <= sub.start {
+                *current = Some(sup); // save the current sup
+                Some(true)
+            } else {
+                Some(false)
+            }
+        };
+        other.iter_intervals().all(|sub| {
+            current
+                .take()
+                .and_then(|sup| contains(sup, sub.clone(), &mut current))
+                .or_else(|| sup_iter.find_map(|sup| contains(sup, sub.clone(), &mut current)))
+                .unwrap_or(false)
+        })
     }
 
     pub fn is_empty(&self) -> bool {
@@ -177,7 +203,10 @@
 
     pub fn insert_all(&mut self) {
         self.clear();
-        self.map.push((0, self.domain.try_into().unwrap()));
+        if let Some(end) = self.domain.checked_sub(1) {
+            self.map.push((0, end.try_into().unwrap()));
+        }
+        debug_assert!(self.check_invariants());
     }
 
     pub fn union(&mut self, other: &IntervalSet<I>) -> bool
@@ -189,8 +218,21 @@
         for range in other.iter_intervals() {
             did_insert |= self.insert_range(range);
         }
+        debug_assert!(self.check_invariants());
         did_insert
     }
+
+    // Check the intervals are valid, sorted and non-adjacent
+    fn check_invariants(&self) -> bool {
+        let mut current: Option<u32> = None;
+        for (start, end) in &self.map {
+            if start > end || current.map_or(false, |x| x + 1 >= *start) {
+                return false;
+            }
+            current = Some(*end);
+        }
+        current.map_or(true, |x| x < self.domain as u32)
+    }
 }
 
 /// This data structure optimizes for cases where the stored bits in each row
diff --git a/compiler/rustc_index/src/interval/tests.rs b/compiler/rustc_index/src/interval/tests.rs
index d90b449..375af60 100644
--- a/compiler/rustc_index/src/interval/tests.rs
+++ b/compiler/rustc_index/src/interval/tests.rs
@@ -2,7 +2,7 @@
 
 #[test]
 fn insert_collapses() {
-    let mut set = IntervalSet::<u32>::new(3000);
+    let mut set = IntervalSet::<u32>::new(10000);
     set.insert_range(9831..=9837);
     set.insert_range(43..=9830);
     assert_eq!(set.iter_intervals().collect::<Vec<_>>(), [43..9838]);
diff --git a/compiler/rustc_index/src/vec.rs b/compiler/rustc_index/src/vec.rs
index 4656994..1a55519 100644
--- a/compiler/rustc_index/src/vec.rs
+++ b/compiler/rustc_index/src/vec.rs
@@ -60,14 +60,8 @@
 unsafe impl<I: Idx, T> Send for IndexVec<I, T> where T: Send {}
 
 impl<S: Encoder, I: Idx, T: Encodable<S>> Encodable<S> for IndexVec<I, T> {
-    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
-        Encodable::encode(&self.raw, s)
-    }
-}
-
-impl<S: Encoder, I: Idx, T: Encodable<S>> Encodable<S> for &IndexVec<I, T> {
-    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
-        Encodable::encode(&self.raw, s)
+    fn encode(&self, s: &mut S) {
+        Encodable::encode(&self.raw, s);
     }
 }
 
diff --git a/compiler/rustc_infer/Cargo.toml b/compiler/rustc_infer/Cargo.toml
index f87ea43..bbc2b76 100644
--- a/compiler/rustc_infer/Cargo.toml
+++ b/compiler/rustc_infer/Cargo.toml
@@ -14,7 +14,6 @@
 rustc_hir = { path = "../rustc_hir" }
 rustc_index = { path = "../rustc_index" }
 rustc_macros = { path = "../rustc_macros" }
-rustc_session = { path = "../rustc_session" }
 rustc_serialize = { path = "../rustc_serialize" }
 rustc_span = { path = "../rustc_span" }
 rustc_target = { path = "../rustc_target" }
diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs
index 39f7d30..ce2698e 100644
--- a/compiler/rustc_infer/src/infer/at.rs
+++ b/compiler/rustc_infer/src/infer/at.rs
@@ -111,6 +111,9 @@
     }
 
     /// Makes `a <: b`, where `a` may or may not be expected.
+    ///
+    /// See [`At::trace_exp`] and [`Trace::sub`] for a version of
+    /// this method that only requires `T: Relate<'tcx>`
     pub fn sub_exp<T>(self, a_is_expected: bool, a: T, b: T) -> InferResult<'tcx, ()>
     where
         T: ToTrace<'tcx>,
@@ -122,6 +125,9 @@
     /// call like `foo(x)`, where `foo: fn(i32)`, you might have
     /// `sup(i32, x)`, since the "expected" type is the type that
     /// appears in the signature.
+    ///
+    /// See [`At::trace`] and [`Trace::sub`] for a version of
+    /// this method that only requires `T: Relate<'tcx>`
     pub fn sup<T>(self, expected: T, actual: T) -> InferResult<'tcx, ()>
     where
         T: ToTrace<'tcx>,
@@ -130,6 +136,9 @@
     }
 
     /// Makes `expected <: actual`.
+    ///
+    /// See [`At::trace`] and [`Trace::sub`] for a version of
+    /// this method that only requires `T: Relate<'tcx>`
     pub fn sub<T>(self, expected: T, actual: T) -> InferResult<'tcx, ()>
     where
         T: ToTrace<'tcx>,
@@ -138,6 +147,9 @@
     }
 
     /// Makes `expected <: actual`.
+    ///
+    /// See [`At::trace_exp`] and [`Trace::eq`] for a version of
+    /// this method that only requires `T: Relate<'tcx>`
     pub fn eq_exp<T>(self, a_is_expected: bool, a: T, b: T) -> InferResult<'tcx, ()>
     where
         T: ToTrace<'tcx>,
@@ -146,6 +158,9 @@
     }
 
     /// Makes `expected <: actual`.
+    ///
+    /// See [`At::trace`] and [`Trace::eq`] for a version of
+    /// this method that only requires `T: Relate<'tcx>`
     pub fn eq<T>(self, expected: T, actual: T) -> InferResult<'tcx, ()>
     where
         T: ToTrace<'tcx>,
@@ -176,6 +191,9 @@
     /// this can result in an error (e.g., if asked to compute LUB of
     /// u32 and i32), it is meaningful to call one of them the
     /// "expected type".
+    ///
+    /// See [`At::trace`] and [`Trace::lub`] for a version of
+    /// this method that only requires `T: Relate<'tcx>`
     pub fn lub<T>(self, expected: T, actual: T) -> InferResult<'tcx, T>
     where
         T: ToTrace<'tcx>,
@@ -186,6 +204,9 @@
     /// Computes the greatest-lower-bound, or mutual subtype, of two
     /// values. As with `lub` order doesn't matter, except for error
     /// cases.
+    ///
+    /// See [`At::trace`] and [`Trace::glb`] for a version of
+    /// this method that only requires `T: Relate<'tcx>`
     pub fn glb<T>(self, expected: T, actual: T) -> InferResult<'tcx, T>
     where
         T: ToTrace<'tcx>,
diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
index 07e51af..9c30c81 100644
--- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
+++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
@@ -11,7 +11,7 @@
 };
 use crate::infer::InferCtxt;
 use rustc_middle::ty::flags::FlagComputation;
-use rustc_middle::ty::fold::{TypeFoldable, TypeFolder};
+use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
 use rustc_middle::ty::subst::GenericArg;
 use rustc_middle::ty::{self, BoundVar, InferConst, List, Ty, TyCtxt, TypeFlags};
 use std::sync::atomic::Ordering;
@@ -476,7 +476,7 @@
     }
 
     fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
-        match ct.val() {
+        match ct.kind() {
             ty::ConstKind::Infer(InferConst::Var(vid)) => {
                 debug!("canonical: const var found with vid {:?}", vid);
                 match self.infcx.probe_const_var(vid) {
@@ -778,7 +778,7 @@
         } else {
             let var = self.canonical_var(info, const_var.into());
             self.tcx().mk_const(ty::ConstS {
-                val: ty::ConstKind::Bound(self.binder_index, var),
+                kind: ty::ConstKind::Bound(self.binder_index, var),
                 ty: self.fold_ty(const_var.ty()),
             })
         }
diff --git a/compiler/rustc_infer/src/infer/canonical/mod.rs b/compiler/rustc_infer/src/infer/canonical/mod.rs
index c7fa252..f251d56 100644
--- a/compiler/rustc_infer/src/infer/canonical/mod.rs
+++ b/compiler/rustc_infer/src/infer/canonical/mod.rs
@@ -149,7 +149,7 @@
                 let placeholder_mapped = ty::PlaceholderConst { universe: universe_mapped, name };
                 self.tcx
                     .mk_const(ty::ConstS {
-                        val: ty::ConstKind::Placeholder(placeholder_mapped),
+                        kind: ty::ConstKind::Placeholder(placeholder_mapped),
                         ty: name.ty,
                     })
                     .into()
diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs
index 5671711..8938ed7 100644
--- a/compiler/rustc_infer/src/infer/canonical/query_response.rs
+++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs
@@ -458,7 +458,7 @@
                     }
                 }
                 GenericArgKind::Const(result_value) => {
-                    if let ty::ConstKind::Bound(debrujin, b) = result_value.val() {
+                    if let ty::ConstKind::Bound(debrujin, b) = result_value.kind() {
                         // ...in which case we would set `canonical_vars[0]` to `Some(const X)`.
 
                         // We only allow a `ty::INNERMOST` index in substitutions.
@@ -547,27 +547,36 @@
     ) -> impl Iterator<Item = PredicateObligation<'tcx>> + 'a + Captures<'tcx> {
         unsubstituted_region_constraints.iter().map(move |&constraint| {
             let predicate = substitute_value(self.tcx, result_subst, constraint);
-            let ty::OutlivesPredicate(k1, r2) = predicate.skip_binder();
-
-            let atom = match k1.unpack() {
-                GenericArgKind::Lifetime(r1) => {
-                    ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(r1, r2))
-                }
-                GenericArgKind::Type(t1) => {
-                    ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(t1, r2))
-                }
-                GenericArgKind::Const(..) => {
-                    // Consts cannot outlive one another, so we don't expect to
-                    // encounter this branch.
-                    span_bug!(cause.span, "unexpected const outlives {:?}", constraint);
-                }
-            };
-            let predicate = predicate.rebind(atom).to_predicate(self.tcx);
-
-            Obligation::new(cause.clone(), param_env, predicate)
+            self.query_outlives_constraint_to_obligation(predicate, cause.clone(), param_env)
         })
     }
 
+    pub fn query_outlives_constraint_to_obligation(
+        &self,
+        predicate: QueryOutlivesConstraint<'tcx>,
+        cause: ObligationCause<'tcx>,
+        param_env: ty::ParamEnv<'tcx>,
+    ) -> Obligation<'tcx, ty::Predicate<'tcx>> {
+        let ty::OutlivesPredicate(k1, r2) = predicate.skip_binder();
+
+        let atom = match k1.unpack() {
+            GenericArgKind::Lifetime(r1) => {
+                ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(r1, r2))
+            }
+            GenericArgKind::Type(t1) => {
+                ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(t1, r2))
+            }
+            GenericArgKind::Const(..) => {
+                // Consts cannot outlive one another, so we don't expect to
+                // encounter this branch.
+                span_bug!(cause.span, "unexpected const outlives {:?}", predicate);
+            }
+        };
+        let predicate = predicate.rebind(atom).to_predicate(self.tcx);
+
+        Obligation::new(cause, param_env, predicate)
+    }
+
     /// Given two sets of values for the same set of canonical variables, unify them.
     /// The second set is produced lazily by supplying indices from the first set.
     fn unify_canonical_vars(
diff --git a/compiler/rustc_infer/src/infer/canonical/substitute.rs b/compiler/rustc_infer/src/infer/canonical/substitute.rs
index 553a11d..45ed4b6 100644
--- a/compiler/rustc_infer/src/infer/canonical/substitute.rs
+++ b/compiler/rustc_infer/src/infer/canonical/substitute.rs
@@ -86,6 +86,6 @@
             c => bug!("{:?} is a const but value is {:?}", bound_ct, c),
         };
 
-        tcx.replace_escaping_bound_vars(value, fld_r, fld_t, fld_c)
+        tcx.replace_escaping_bound_vars_uncached(value, fld_r, fld_t, fld_c)
     }
 }
diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs
index aa3f060..67dcb6e 100644
--- a/compiler/rustc_infer/src/infer/combine.rs
+++ b/compiler/rustc_infer/src/infer/combine.rs
@@ -1,26 +1,26 @@
-///////////////////////////////////////////////////////////////////////////
-// # Type combining
-//
-// There are four type combiners: equate, sub, lub, and glb.  Each
-// implements the trait `Combine` and contains methods for combining
-// two instances of various things and yielding a new instance.  These
-// combiner methods always yield a `Result<T>`.  There is a lot of
-// common code for these operations, implemented as default methods on
-// the `Combine` trait.
-//
-// Each operation may have side-effects on the inference context,
-// though these can be unrolled using snapshots. On success, the
-// LUB/GLB operations return the appropriate bound. The Eq and Sub
-// operations generally return the first operand.
-//
-// ## Contravariance
-//
-// When you are relating two things which have a contravariant
-// relationship, you should use `contratys()` or `contraregions()`,
-// rather than inversing the order of arguments!  This is necessary
-// because the order of arguments is not relevant for LUB and GLB.  It
-// is also useful to track which value is the "expected" value in
-// terms of error reporting.
+//! There are four type combiners: [Equate], [Sub], [Lub], and [Glb].
+//! Each implements the trait [TypeRelation] and contains methods for
+//! combining two instances of various things and yielding a new instance.
+//! These combiner methods always yield a `Result<T>`. To relate two
+//! types, you can use `infcx.at(cause, param_env)` which then allows
+//! you to use the relevant methods of [At](super::at::At).
+//!
+//! Combiners mostly do their specific behavior and then hand off the
+//! bulk of the work to [InferCtxt::super_combine_tys] and
+//! [InferCtxt::super_combine_consts].
+//!
+//! Combining two types may have side-effects on the inference contexts
+//! which can be undone by using snapshots. You probably want to use
+//! either [InferCtxt::commit_if_ok] or [InferCtxt::probe].
+//!
+//! On success, the  LUB/GLB operations return the appropriate bound. The
+//! return value of `Equate` or `Sub` shouldn't really be used.
+//!
+//! ## Contravariance
+//!
+//! We explicitly track which argument is expected using
+//! [TypeRelation::a_is_expected], so when dealing with contravariance
+//! this should be correctly updated.
 
 use super::equate::Equate;
 use super::glb::Glb;
@@ -142,7 +142,7 @@
 
         let a_is_expected = relation.a_is_expected();
 
-        match (a.val(), b.val()) {
+        match (a.kind(), b.kind()) {
             (
                 ty::ConstKind::Infer(InferConst::Var(a_vid)),
                 ty::ConstKind::Infer(InferConst::Var(b_vid)),
@@ -726,7 +726,7 @@
     ) -> RelateResult<'tcx, ty::Const<'tcx>> {
         assert_eq!(c, c2); // we are abusing TypeRelation here; both LHS and RHS ought to be ==
 
-        match c.val() {
+        match c.kind() {
             ty::ConstKind::Infer(InferConst::Var(vid)) => {
                 let mut inner = self.infcx.inner.borrow_mut();
                 let variable_table = &mut inner.const_unification_table();
@@ -761,7 +761,7 @@
                 )?;
                 Ok(self.tcx().mk_const(ty::ConstS {
                     ty: c.ty(),
-                    val: ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }),
+                    kind: ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }),
                 }))
             }
             _ => relate::super_relate_consts(self, c, c),
@@ -776,21 +776,6 @@
     fn const_equate_obligation(&mut self, a: ty::Const<'tcx>, b: ty::Const<'tcx>);
 }
 
-pub trait RelateResultCompare<'tcx, T> {
-    fn compare<F>(&self, t: T, f: F) -> RelateResult<'tcx, T>
-    where
-        F: FnOnce() -> TypeError<'tcx>;
-}
-
-impl<'tcx, T: Clone + PartialEq> RelateResultCompare<'tcx, T> for RelateResult<'tcx, T> {
-    fn compare<F>(&self, t: T, f: F) -> RelateResult<'tcx, T>
-    where
-        F: FnOnce() -> TypeError<'tcx>,
-    {
-        self.clone().and_then(|s| if s == t { self.clone() } else { Err(f()) })
-    }
-}
-
 pub fn const_unification_error<'tcx>(
     a_is_expected: bool,
     (a, b): (ty::Const<'tcx>, ty::Const<'tcx>),
@@ -956,7 +941,7 @@
         debug_assert_eq!(c, _c);
         debug!("ConstInferUnifier: c={:?}", c);
 
-        match c.val() {
+        match c.kind() {
             ty::ConstKind::Infer(InferConst::Var(vid)) => {
                 // Check if the current unification would end up
                 // unifying `target_vid` with a const which contains
@@ -1007,7 +992,7 @@
                 )?;
                 Ok(self.tcx().mk_const(ty::ConstS {
                     ty: c.ty(),
-                    val: ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }),
+                    kind: ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }),
                 }))
             }
             _ => relate::super_relate_consts(self, c, c),
diff --git a/compiler/rustc_infer/src/infer/equate.rs b/compiler/rustc_infer/src/infer/equate.rs
index ef6d464..3b1798c 100644
--- a/compiler/rustc_infer/src/infer/equate.rs
+++ b/compiler/rustc_infer/src/infer/equate.rs
@@ -153,12 +153,12 @@
     {
         if a.skip_binder().has_escaping_bound_vars() || b.skip_binder().has_escaping_bound_vars() {
             self.fields.higher_ranked_sub(a, b, self.a_is_expected)?;
-            self.fields.higher_ranked_sub(b, a, self.a_is_expected)
+            self.fields.higher_ranked_sub(b, a, self.a_is_expected)?;
         } else {
             // Fast path for the common case.
             self.relate(a.skip_binder(), b.skip_binder())?;
-            Ok(a)
         }
+        Ok(a)
     }
 }
 
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index 02caae7..b94d205 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -67,12 +67,10 @@
 use rustc_middle::dep_graph::DepContext;
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::{
-    self,
-    error::TypeError,
-    subst::{GenericArgKind, Subst, SubstsRef},
-    Binder, EarlyBinder, List, Region, Ty, TyCtxt, TypeFoldable,
+    self, error::TypeError, Binder, List, Region, Subst, Ty, TyCtxt, TypeFoldable,
+    TypeSuperFoldable,
 };
-use rustc_span::{sym, BytePos, DesugaringKind, Pos, Span};
+use rustc_span::{sym, symbol::kw, BytePos, DesugaringKind, Pos, Span};
 use rustc_target::spec::abi;
 use std::ops::ControlFlow;
 use std::{cmp, fmt, iter};
@@ -161,35 +159,45 @@
             {
                 sp = param.span;
             }
-            (format!("the lifetime `{}` as defined here", br.name), sp)
+            let text = if br.has_name() {
+                format!("the lifetime `{}` as defined here", br.name)
+            } else {
+                format!("the anonymous lifetime as defined here")
+            };
+            (text, sp)
         }
-        ty::ReFree(ty::FreeRegion {
-            bound_region: ty::BoundRegionKind::BrNamed(_, name), ..
-        }) => {
-            let mut sp = sm.guess_head_span(tcx.def_span(scope));
-            if let Some(param) =
-                tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(name))
+        ty::ReFree(ref fr) => {
+            if !fr.bound_region.is_named()
+                && let Some((ty, _)) = find_anon_type(tcx, region, &fr.bound_region)
             {
-                sp = param.span;
-            }
-            (format!("the lifetime `{}` as defined here", name), sp)
-        }
-        ty::ReFree(ref fr) => match fr.bound_region {
-            ty::BrAnon(idx) => {
-                if let Some((ty, _)) = find_anon_type(tcx, region, &fr.bound_region) {
-                    ("the anonymous lifetime defined here".to_string(), ty.span)
-                } else {
-                    (
+                ("the anonymous lifetime defined here".to_string(), ty.span)
+            } else {
+                match fr.bound_region {
+                    ty::BoundRegionKind::BrNamed(_, name) => {
+                        let mut sp = sm.guess_head_span(tcx.def_span(scope));
+                        if let Some(param) =
+                            tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(name))
+                        {
+                            sp = param.span;
+                        }
+                        let text = if name == kw::UnderscoreLifetime {
+                            format!("the anonymous lifetime as defined here")
+                        } else {
+                            format!("the lifetime `{}` as defined here", name)
+                        };
+                        (text, sp)
+                    }
+                    ty::BrAnon(idx) => (
                         format!("the anonymous lifetime #{} defined here", idx + 1),
-                        tcx.def_span(scope),
-                    )
+                        tcx.def_span(scope)
+                    ),
+                    _ => (
+                        format!("the lifetime `{}` as defined here", region),
+                        sm.guess_head_span(tcx.def_span(scope)),
+                    ),
                 }
             }
-            _ => (
-                format!("the lifetime `{}` as defined here", region),
-                sm.guess_head_span(tcx.def_span(scope)),
-            ),
-        },
+        }
         _ => bug!(),
     }
 }
@@ -342,7 +350,7 @@
 }
 
 impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
-    pub fn report_region_errors(&self, errors: &Vec<RegionResolutionError<'tcx>>) {
+    pub fn report_region_errors(&self, errors: &[RegionResolutionError<'tcx>]) {
         debug!("report_region_errors(): {} errors to start", errors.len());
 
         // try to pre-process the errors, which will group some of them
@@ -609,7 +617,14 @@
                 if !matches!(ty.kind(), ty::Infer(ty::InferTy::TyVar(_) | ty::InferTy::FreshTy(_)))
                 {
                     // don't show type `_`
-                    err.span_label(span, format!("this expression has type `{}`", ty));
+                    if span.desugaring_kind() == Some(DesugaringKind::ForLoop)
+                    && let ty::Adt(def, substs) = ty.kind()
+                    && Some(def.did()) == self.tcx.get_diagnostic_item(sym::Option)
+                    {
+                        err.span_label(span, format!("this is an iterator with items of type `{}`", substs.type_at(0)));
+                    } else {
+                        err.span_label(span, format!("this expression has type `{}`", ty));
+                    }
                 }
                 if let Some(ty::error::ExpectedFound { found, .. }) = exp_found
                     && ty.is_box() && ty.boxed_ty() == found
@@ -655,7 +670,7 @@
                                 err.span_suggestion(
                                     source_map.end_point(cause.span),
                                     "try removing this `?`",
-                                    "".to_string(),
+                                    "",
                                     Applicability::MachineApplicable,
                                 );
                             }
@@ -711,14 +726,14 @@
                             err.span_suggestion_short(
                                 sp,
                                 "consider removing this semicolon and boxing the expressions",
-                                String::new(),
+                                "",
                                 Applicability::MachineApplicable,
                             );
                         } else {
                             err.span_suggestion_short(
                                 sp,
                                 "consider removing this semicolon",
-                                String::new(),
+                                "",
                                 Applicability::MachineApplicable,
                             );
                         }
@@ -761,7 +776,7 @@
                         err.span_suggestion_short(
                             sp,
                             "consider removing this semicolon",
-                            String::new(),
+                            "",
                             Applicability::MachineApplicable,
                         );
                     }
@@ -909,10 +924,13 @@
         mut t1_out: &mut DiagnosticStyledString,
         mut t2_out: &mut DiagnosticStyledString,
         path: String,
-        sub: ty::subst::SubstsRef<'tcx>,
+        sub: &'tcx [ty::GenericArg<'tcx>],
         other_path: String,
         other_ty: Ty<'tcx>,
     ) -> Option<()> {
+        // FIXME/HACK: Go back to `SubstsRef` to use its inherent methods,
+        // ideally that shouldn't be necessary.
+        let sub = self.tcx.intern_substs(sub);
         for (i, ta) in sub.types().enumerate() {
             if ta == other_ty {
                 self.highlight_outer(&mut t1_out, &mut t2_out, path, sub, i, other_ty);
@@ -943,45 +961,6 @@
         }
     }
 
-    /// For generic types with parameters with defaults, remove the parameters corresponding to
-    /// the defaults. This repeats a lot of the logic found in `ty::print::pretty`.
-    fn strip_generic_default_params(
-        &self,
-        def_id: DefId,
-        substs: ty::subst::SubstsRef<'tcx>,
-    ) -> SubstsRef<'tcx> {
-        let generics = self.tcx.generics_of(def_id);
-        let mut num_supplied_defaults = 0;
-
-        let default_params = generics.params.iter().rev().filter_map(|param| match param.kind {
-            ty::GenericParamDefKind::Type { has_default: true, .. } => Some(param.def_id),
-            ty::GenericParamDefKind::Const { has_default: true } => Some(param.def_id),
-            _ => None,
-        });
-        for (def_id, actual) in iter::zip(default_params, substs.iter().rev()) {
-            match actual.unpack() {
-                GenericArgKind::Const(c) => {
-                    if EarlyBinder(self.tcx.const_param_default(def_id)).subst(self.tcx, substs)
-                        != c
-                    {
-                        break;
-                    }
-                }
-                GenericArgKind::Type(ty) => {
-                    if self.tcx.bound_type_of(def_id).subst(self.tcx, substs) != ty {
-                        break;
-                    }
-                }
-                _ => break,
-            }
-            num_supplied_defaults += 1;
-        }
-        let len = generics.params.len();
-        let mut generics = generics.clone();
-        generics.params.truncate(len - num_supplied_defaults);
-        substs.truncate_to(self.tcx, &generics)
-    }
-
     /// Given two `fn` signatures highlight only sub-parts that are different.
     fn cmp_fn_sig(
         &self,
@@ -1139,8 +1118,10 @@
             (&ty::Adt(def1, sub1), &ty::Adt(def2, sub2)) => {
                 let did1 = def1.did();
                 let did2 = def2.did();
-                let sub_no_defaults_1 = self.strip_generic_default_params(did1, sub1);
-                let sub_no_defaults_2 = self.strip_generic_default_params(did2, sub2);
+                let sub_no_defaults_1 =
+                    self.tcx.generics_of(did1).own_substs_no_defaults(self.tcx, sub1);
+                let sub_no_defaults_2 =
+                    self.tcx.generics_of(did2).own_substs_no_defaults(self.tcx, sub2);
                 let mut values = (DiagnosticStyledString::new(), DiagnosticStyledString::new());
                 let path1 = self.tcx.def_path_str(did1);
                 let path2 = self.tcx.def_path_str(did2);
@@ -1442,6 +1423,10 @@
     /// the message in `secondary_span` as the primary label, and apply the message that would
     /// otherwise be used for the primary label on the `secondary_span` `Span`. This applies on
     /// E0271, like `src/test/ui/issues/issue-39970.stderr`.
+    #[tracing::instrument(
+        level = "debug",
+        skip(self, diag, secondary_span, swap_secondary_and_primary, force_label)
+    )]
     pub fn note_type_err(
         &self,
         diag: &mut Diagnostic,
@@ -1453,7 +1438,6 @@
         force_label: bool,
     ) {
         let span = cause.span(self.tcx);
-        debug!("note_type_err cause={:?} values={:?}, terr={:?}", cause, values, terr);
 
         // For some types of errors, expected-found does not make
         // sense, so just ignore the values we were given.
@@ -1604,7 +1588,9 @@
                             Mismatch::Variable(infer::ExpectedFound { expected, found }),
                         )
                     }
-                    ValuePairs::TraitRefs(_) => (false, Mismatch::Fixed("trait")),
+                    ValuePairs::TraitRefs(_) | ValuePairs::PolyTraitRefs(_) => {
+                        (false, Mismatch::Fixed("trait"))
+                    }
                     _ => (false, Mismatch::Fixed("type")),
                 };
                 let vals = match self.values_str(values) {
@@ -1621,9 +1607,9 @@
             }
         };
 
-        // Ignore msg for object safe coercion
-        // since E0038 message will be printed
         match terr {
+            // Ignore msg for object safe coercion
+            // since E0038 message will be printed
             TypeError::ObjectUnsafeCoercion(_) => {}
             _ => {
                 let mut label_or_note = |span: Span, msg: &str| {
@@ -1774,6 +1760,8 @@
         // It reads better to have the error origin as the final
         // thing.
         self.note_error_origin(diag, cause, exp_found, terr);
+
+        debug!(?diag);
     }
 
     fn suggest_tuple_pattern(
@@ -1947,7 +1935,7 @@
                 diag.span_suggestion_verbose(
                     exp_span.shrink_to_hi(),
                     "consider `await`ing on the `Future`",
-                    ".await".to_string(),
+                    ".await",
                     Applicability::MaybeIncorrect,
                 );
             }
@@ -1957,7 +1945,7 @@
                     diag.span_suggestion_verbose(
                         span.shrink_to_hi(),
                         "consider `await`ing on the `Future`",
-                        ".await".to_string(),
+                        ".await",
                         Applicability::MaybeIncorrect,
                     );
                 }
@@ -2523,11 +2511,7 @@
                     labeled_user_string
                 );
                 let pred = format!("{}: {}", bound_kind, sub);
-                let suggestion = format!(
-                    "{} {}",
-                    if !generics.predicates.is_empty() { "," } else { " where" },
-                    pred,
-                );
+                let suggestion = format!("{} {}", generics.add_where_or_trailing_comma(), pred,);
                 err.span_suggestion(
                     generics.tail_span_for_predicate_suggestion(),
                     "consider adding a where clause",
@@ -2540,7 +2524,7 @@
                 ty::ReEarlyBound(ty::EarlyBoundRegion { name, .. })
                 | ty::ReFree(ty::FreeRegion { bound_region: ty::BrNamed(_, name), .. }),
                 _,
-            ) => {
+            ) if name != kw::UnderscoreLifetime => {
                 // Does the required lifetime have a nice name we can print?
                 let mut err = struct_span_err!(
                     self.tcx.sess,
diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
index 62edfc6..20b9ed9 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
@@ -1,263 +1,23 @@
 use crate::infer::type_variable::TypeVariableOriginKind;
-use crate::infer::{InferCtxt, Symbol};
-use rustc_errors::{
-    pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
-};
+use crate::infer::InferCtxt;
+use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed};
 use rustc_hir as hir;
-use rustc_hir::def::{DefKind, Namespace};
+use rustc_hir::def::Res;
+use rustc_hir::def::{CtorOf, DefKind, Namespace};
 use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::{self, Visitor};
-use rustc_hir::{Body, Expr, ExprKind, FnRetTy, HirId, Local, MatchSource, Pat};
+use rustc_hir::{Body, Expr, ExprKind, FnRetTy, HirId, Local, LocalSource};
 use rustc_middle::hir::nested_filter;
 use rustc_middle::infer::unify_key::ConstVariableOriginKind;
-use rustc_middle::ty::print::Print;
-use rustc_middle::ty::subst::{GenericArg, GenericArgKind};
-use rustc_middle::ty::{self, Const, DefIdTree, InferConst, Ty, TyCtxt, TypeFoldable, TypeFolder};
-use rustc_span::symbol::kw;
-use rustc_span::{sym, Span};
+use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
+use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter, Print, Printer};
+use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst, SubstsRef};
+use rustc_middle::ty::{self, DefIdTree, InferConst};
+use rustc_middle::ty::{Ty, TyCtxt, TypeckResults};
+use rustc_span::symbol::{kw, Ident};
+use rustc_span::{BytePos, Span};
 use std::borrow::Cow;
-
-struct FindHirNodeVisitor<'a, 'tcx> {
-    infcx: &'a InferCtxt<'a, 'tcx>,
-    target: GenericArg<'tcx>,
-    target_span: Span,
-    found_node_ty: Option<Ty<'tcx>>,
-    found_local_pattern: Option<&'tcx Pat<'tcx>>,
-    found_arg_pattern: Option<&'tcx Pat<'tcx>>,
-    found_closure: Option<&'tcx Expr<'tcx>>,
-    found_method_call: Option<&'tcx Expr<'tcx>>,
-    found_exact_method_call: Option<&'tcx Expr<'tcx>>,
-    found_for_loop_iter: Option<&'tcx Expr<'tcx>>,
-    found_use_diagnostic: Option<UseDiagnostic<'tcx>>,
-}
-
-impl<'a, 'tcx> FindHirNodeVisitor<'a, 'tcx> {
-    fn new(infcx: &'a InferCtxt<'a, 'tcx>, target: GenericArg<'tcx>, target_span: Span) -> Self {
-        Self {
-            infcx,
-            target,
-            target_span,
-            found_node_ty: None,
-            found_local_pattern: None,
-            found_arg_pattern: None,
-            found_closure: None,
-            found_method_call: None,
-            found_exact_method_call: None,
-            found_for_loop_iter: None,
-            found_use_diagnostic: None,
-        }
-    }
-
-    fn node_type_opt(&self, hir_id: HirId) -> Option<Ty<'tcx>> {
-        self.infcx.in_progress_typeck_results?.borrow().node_type_opt(hir_id)
-    }
-
-    fn node_ty_contains_target(&self, hir_id: HirId) -> Option<Ty<'tcx>> {
-        self.node_type_opt(hir_id).map(|ty| self.infcx.resolve_vars_if_possible(ty)).filter(|ty| {
-            ty.walk().any(|inner| {
-                inner == self.target
-                    || match (inner.unpack(), self.target.unpack()) {
-                        (GenericArgKind::Type(inner_ty), GenericArgKind::Type(target_ty)) => {
-                            use ty::{Infer, TyVar};
-                            match (inner_ty.kind(), target_ty.kind()) {
-                                (&Infer(TyVar(a_vid)), &Infer(TyVar(b_vid))) => self
-                                    .infcx
-                                    .inner
-                                    .borrow_mut()
-                                    .type_variables()
-                                    .sub_unified(a_vid, b_vid),
-                                _ => false,
-                            }
-                        }
-                        _ => false,
-                    }
-            })
-        })
-    }
-
-    /// Determine whether the expression, assumed to be the callee within a `Call`,
-    /// corresponds to the `From::from` emitted in desugaring of the `?` operator.
-    fn is_try_conversion(&self, callee: &Expr<'tcx>) -> bool {
-        self.infcx
-            .trait_def_from_hir_fn(callee.hir_id)
-            .map_or(false, |def_id| self.infcx.is_try_conversion(callee.span, def_id))
-    }
-}
-
-impl<'a, 'tcx> Visitor<'tcx> for FindHirNodeVisitor<'a, 'tcx> {
-    type NestedFilter = nested_filter::OnlyBodies;
-
-    fn nested_visit_map(&mut self) -> Self::Map {
-        self.infcx.tcx.hir()
-    }
-
-    fn visit_local(&mut self, local: &'tcx Local<'tcx>) {
-        if let (None, Some(ty)) =
-            (self.found_local_pattern, self.node_ty_contains_target(local.hir_id))
-        {
-            self.found_local_pattern = Some(&*local.pat);
-            self.found_node_ty = Some(ty);
-        }
-        intravisit::walk_local(self, local);
-    }
-
-    fn visit_body(&mut self, body: &'tcx Body<'tcx>) {
-        for param in body.params {
-            if let (None, Some(ty)) =
-                (self.found_arg_pattern, self.node_ty_contains_target(param.hir_id))
-            {
-                self.found_arg_pattern = Some(&*param.pat);
-                self.found_node_ty = Some(ty);
-            }
-        }
-        intravisit::walk_body(self, body);
-    }
-
-    fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
-        if let ExprKind::Match(scrutinee, [_, arm], MatchSource::ForLoopDesugar) = expr.kind
-            && let Some(pat) = arm.pat.for_loop_some()
-            && let Some(ty) = self.node_ty_contains_target(pat.hir_id)
-        {
-            self.found_for_loop_iter = Some(scrutinee);
-            self.found_node_ty = Some(ty);
-            return;
-        }
-        if let ExprKind::MethodCall(segment, exprs, _) = expr.kind
-            && segment.ident.span == self.target_span
-            && Some(self.target) == self.infcx.in_progress_typeck_results.and_then(|typeck_results| {
-                typeck_results
-                    .borrow()
-                    .node_type_opt(exprs.first().unwrap().hir_id)
-                    .map(Into::into)
-            })
-        {
-            self.found_exact_method_call = Some(&expr);
-            return;
-        }
-
-        // FIXME(const_generics): Currently, any uninferred `const` generics arguments
-        // are handled specially, but instead they should be handled in `annotate_method_call`,
-        // which currently doesn't work because this evaluates to `false` for const arguments.
-        // See https://github.com/rust-lang/rust/pull/77758 for more details.
-        if let Some(ty) = self.node_ty_contains_target(expr.hir_id) {
-            match expr.kind {
-                ExprKind::Closure(..) => self.found_closure = Some(&expr),
-                ExprKind::MethodCall(..) => self.found_method_call = Some(&expr),
-
-                // If the given expression falls within the target span and is a
-                // `From::from(e)` call emitted during desugaring of the `?` operator,
-                // extract the types inferred before and after the call
-                ExprKind::Call(callee, [arg])
-                    if self.target_span.contains(expr.span)
-                        && self.found_use_diagnostic.is_none()
-                        && self.is_try_conversion(callee) =>
-                {
-                    self.found_use_diagnostic = self.node_type_opt(arg.hir_id).map(|pre_ty| {
-                        UseDiagnostic::TryConversion { pre_ty, post_ty: ty, span: callee.span }
-                    });
-                }
-                _ => {}
-            }
-        }
-        intravisit::walk_expr(self, expr);
-    }
-}
-
-/// An observation about the use site of a type to be emitted as an additional
-/// note in an inference failure error.
-enum UseDiagnostic<'tcx> {
-    /// Records the types inferred before and after `From::from` is called on the
-    /// error value within the desugaring of the `?` operator.
-    TryConversion { pre_ty: Ty<'tcx>, post_ty: Ty<'tcx>, span: Span },
-}
-
-impl UseDiagnostic<'_> {
-    /// Return a descriptor of the value at the use site
-    fn descr(&self) -> &'static str {
-        match self {
-            Self::TryConversion { .. } => "error for `?` operator",
-        }
-    }
-
-    /// Return a descriptor of the type at the use site
-    fn type_descr(&self) -> &'static str {
-        match self {
-            Self::TryConversion { .. } => "error type for `?` operator",
-        }
-    }
-
-    fn applies_to(&self, span: Span) -> bool {
-        match *self {
-            // In some cases the span for an inference failure due to try
-            // conversion contains the antecedent expression as well as the `?`
-            Self::TryConversion { span: s, .. } => span.contains(s) && span.hi() == s.hi(),
-        }
-    }
-
-    fn attach_note(&self, err: &mut Diagnostic) {
-        match *self {
-            Self::TryConversion { pre_ty, post_ty, .. } => {
-                let intro = "`?` implicitly converts the error value";
-
-                let msg = match (pre_ty.is_ty_infer(), post_ty.is_ty_infer()) {
-                    (true, true) => format!("{} using the `From` trait", intro),
-                    (false, true) => {
-                        format!("{} into a type implementing `From<{}>`", intro, pre_ty)
-                    }
-                    (true, false) => {
-                        format!("{} into `{}` using the `From` trait", intro, post_ty)
-                    }
-                    (false, false) => {
-                        format!(
-                            "{} into `{}` using its implementation of `From<{}>`",
-                            intro, post_ty, pre_ty
-                        )
-                    }
-                };
-
-                err.note(&msg);
-            }
-        }
-    }
-}
-
-/// Suggest giving an appropriate return type to a closure expression.
-fn closure_return_type_suggestion(
-    err: &mut Diagnostic,
-    output: &FnRetTy<'_>,
-    body: &Body<'_>,
-    ret: &str,
-) {
-    let (arrow, post) = match output {
-        FnRetTy::DefaultReturn(_) => ("-> ", " "),
-        _ => ("", ""),
-    };
-    let suggestion = match body.value.kind {
-        ExprKind::Block(..) => vec![(output.span(), format!("{}{}{}", arrow, ret, post))],
-        _ => vec![
-            (output.span(), format!("{}{}{}{{ ", arrow, ret, post)),
-            (body.value.span.shrink_to_hi(), " }".to_string()),
-        ],
-    };
-    err.multipart_suggestion(
-        "give this closure an explicit return type without `_` placeholders",
-        suggestion,
-        Applicability::HasPlaceholders,
-    );
-}
-
-/// Given a closure signature, return a `String` containing a list of all its argument types.
-fn closure_args(fn_sig: &ty::PolyFnSig<'_>) -> String {
-    fn_sig
-        .inputs()
-        .skip_binder()
-        .iter()
-        .next()
-        .map(|args| {
-            args.tuple_fields().iter().map(|arg| arg.to_string()).collect::<Vec<_>>().join(", ")
-        })
-        .unwrap_or_default()
-}
+use std::iter;
 
 pub enum TypeAnnotationNeeded {
     /// ```compile_fail,E0282
@@ -296,9 +56,8 @@
 
 /// Data on the parent definition where a generic argument was declared.
 pub struct InferenceDiagnosticsParentData {
-    pub prefix: &'static str,
-    pub name: String,
-    pub def_id: DefId,
+    prefix: &'static str,
+    name: String,
 }
 
 pub enum UnderspecifiedArgKind {
@@ -306,52 +65,58 @@
     Const { is_parameter: bool },
 }
 
-impl UnderspecifiedArgKind {
-    fn descr(&self) -> &'static str {
-        match self {
-            Self::Type { .. } => "type",
-            Self::Const { .. } => "const",
-        }
-    }
-}
-
 impl InferenceDiagnosticsData {
     /// Generate a label for a generic argument which can't be inferred. When not
     /// much is known about the argument, `use_diag` may be used to describe the
     /// labeled value.
-    fn cannot_infer_msg(&self, use_diag: Option<&UseDiagnostic<'_>>) -> String {
+    fn cannot_infer_msg(&self) -> String {
         if self.name == "_" && matches!(self.kind, UnderspecifiedArgKind::Type { .. }) {
-            if let Some(use_diag) = use_diag {
-                return format!("cannot infer type of {}", use_diag.descr());
-            }
-
             return "cannot infer type".to_string();
         }
 
-        let suffix = match (&self.parent, use_diag) {
-            (Some(parent), _) => format!(" declared on the {} `{}`", parent.prefix, parent.name),
-            (None, Some(use_diag)) => format!(" in {}", use_diag.type_descr()),
-            (None, None) => String::new(),
+        let suffix = match &self.parent {
+            Some(parent) => parent.suffix_string(),
+            None => String::new(),
         };
 
         // For example: "cannot infer type for type parameter `T`"
         format!("cannot infer {} `{}`{}", self.kind.prefix_string(), self.name, suffix)
     }
+
+    fn where_x_is_specified(&self, in_type: Ty<'_>) -> String {
+        if in_type.is_ty_infer() {
+            String::new()
+        } else if self.name == "_" {
+            // FIXME: Consider specializing this message if there is a single `_`
+            // in the type.
+            ", where the placeholders `_` are specified".to_string()
+        } else {
+            format!(", where the {} `{}` is specified", self.kind.prefix_string(), self.name)
+        }
+    }
 }
 
 impl InferenceDiagnosticsParentData {
-    fn for_def_id(tcx: TyCtxt<'_>, def_id: DefId) -> Option<InferenceDiagnosticsParentData> {
-        let parent_def_id = tcx.parent(def_id);
-
+    fn for_parent_def_id(
+        tcx: TyCtxt<'_>,
+        parent_def_id: DefId,
+    ) -> Option<InferenceDiagnosticsParentData> {
         let parent_name =
             tcx.def_key(parent_def_id).disambiguated_data.data.get_opt_name()?.to_string();
 
         Some(InferenceDiagnosticsParentData {
             prefix: tcx.def_kind(parent_def_id).descr(parent_def_id),
             name: parent_name,
-            def_id: parent_def_id,
         })
     }
+
+    fn for_def_id(tcx: TyCtxt<'_>, def_id: DefId) -> Option<InferenceDiagnosticsParentData> {
+        Self::for_parent_def_id(tcx, tcx.parent(def_id))
+    }
+
+    fn suffix_string(&self) -> String {
+        format!(" declared on the {} `{}`", self.prefix, self.name)
+    }
 }
 
 impl UnderspecifiedArgKind {
@@ -364,6 +129,80 @@
     }
 }
 
+fn fmt_printer<'a, 'tcx>(infcx: &'a InferCtxt<'_, 'tcx>, ns: Namespace) -> FmtPrinter<'a, 'tcx> {
+    let mut printer = FmtPrinter::new(infcx.tcx, ns);
+    let ty_getter = move |ty_vid| {
+        if infcx.probe_ty_var(ty_vid).is_ok() {
+            warn!("resolved ty var in error message");
+        }
+        if let TypeVariableOriginKind::TypeParameterDefinition(name, _) =
+            infcx.inner.borrow_mut().type_variables().var_origin(ty_vid).kind
+        {
+            Some(name.to_string())
+        } else {
+            None
+        }
+    };
+    printer.ty_infer_name_resolver = Some(Box::new(ty_getter));
+    let const_getter = move |ct_vid| {
+        if infcx.probe_const_var(ct_vid).is_ok() {
+            warn!("resolved const var in error message");
+        }
+        if let ConstVariableOriginKind::ConstParameterDefinition(name, _) =
+            infcx.inner.borrow_mut().const_unification_table().probe_value(ct_vid).origin.kind
+        {
+            return Some(name.to_string());
+        } else {
+            None
+        }
+    };
+    printer.const_infer_name_resolver = Some(Box::new(const_getter));
+    printer
+}
+
+fn ty_to_string<'tcx>(infcx: &InferCtxt<'_, 'tcx>, ty: Ty<'tcx>) -> String {
+    let printer = fmt_printer(infcx, Namespace::TypeNS);
+    let ty = infcx.resolve_vars_if_possible(ty);
+    match ty.kind() {
+        // We don't want the regular output for `fn`s because it includes its path in
+        // invalid pseudo-syntax, we want the `fn`-pointer output instead.
+        ty::FnDef(..) => ty.fn_sig(infcx.tcx).print(printer).unwrap().into_buffer(),
+        // FIXME: The same thing for closures, but this only works when the closure
+        // does not capture anything.
+        //
+        // We do have to hide the `extern "rust-call"` ABI in that case though,
+        // which is too much of a bother for now.
+        _ => ty.print(printer).unwrap().into_buffer(),
+    }
+}
+
+/// We don't want to directly use `ty_to_string` for closures as their type isn't really
+/// something users are familar with. Directly printing the `fn_sig` of closures also
+/// doesn't work as they actually use the "rust-call" API.
+fn closure_as_fn_str<'tcx>(infcx: &InferCtxt<'_, 'tcx>, ty: Ty<'tcx>) -> String {
+    let ty::Closure(_, substs) = ty.kind() else { unreachable!() };
+    let fn_sig = substs.as_closure().sig();
+    let args = fn_sig
+        .inputs()
+        .skip_binder()
+        .iter()
+        .next()
+        .map(|args| {
+            args.tuple_fields()
+                .iter()
+                .map(|arg| ty_to_string(infcx, arg))
+                .collect::<Vec<_>>()
+                .join(", ")
+        })
+        .unwrap_or_default();
+    let ret = if fn_sig.output().skip_binder().is_unit() {
+        String::new()
+    } else {
+        format!(" -> {}", ty_to_string(infcx, fn_sig.output().skip_binder()))
+    };
+    format!("fn({}){}", args, ret)
+}
+
 impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
     /// Extracts data used by diagnostic for either types or constants
     /// which were stuck during inference.
@@ -400,79 +239,55 @@
                 if let Some(highlight) = highlight {
                     printer.region_highlight_mode = highlight;
                 }
-                let name = ty.print(printer).unwrap().into_buffer();
                 InferenceDiagnosticsData {
-                    name,
+                    name: ty.print(printer).unwrap().into_buffer(),
                     span: None,
                     kind: UnderspecifiedArgKind::Type { prefix: ty.prefix_string(self.tcx) },
                     parent: None,
                 }
             }
             GenericArgKind::Const(ct) => {
-                match ct.val() {
-                    ty::ConstKind::Infer(InferConst::Var(vid)) => {
-                        let origin = self
-                            .inner
-                            .borrow_mut()
-                            .const_unification_table()
-                            .probe_value(vid)
-                            .origin;
-                        if let ConstVariableOriginKind::ConstParameterDefinition(name, def_id) =
-                            origin.kind
-                        {
-                            return InferenceDiagnosticsData {
-                                name: name.to_string(),
-                                span: Some(origin.span),
-                                kind: UnderspecifiedArgKind::Const { is_parameter: true },
-                                parent: InferenceDiagnosticsParentData::for_def_id(
-                                    self.tcx, def_id,
-                                ),
-                            };
-                        }
-
-                        debug_assert!(!origin.span.is_dummy());
-                        let mut printer = ty::print::FmtPrinter::new(self.tcx, Namespace::ValueNS);
-                        if let Some(highlight) = highlight {
-                            printer.region_highlight_mode = highlight;
-                        }
-                        let name = ct.print(printer).unwrap().into_buffer();
-                        InferenceDiagnosticsData {
-                            name,
+                if let ty::ConstKind::Infer(InferConst::Var(vid)) = ct.kind() {
+                    let origin =
+                        self.inner.borrow_mut().const_unification_table().probe_value(vid).origin;
+                    if let ConstVariableOriginKind::ConstParameterDefinition(name, def_id) =
+                        origin.kind
+                    {
+                        return InferenceDiagnosticsData {
+                            name: name.to_string(),
                             span: Some(origin.span),
-                            kind: UnderspecifiedArgKind::Const { is_parameter: false },
-                            parent: None,
-                        }
+                            kind: UnderspecifiedArgKind::Const { is_parameter: true },
+                            parent: InferenceDiagnosticsParentData::for_def_id(self.tcx, def_id),
+                        };
                     }
-                    ty::ConstKind::Unevaluated(ty::Unevaluated { substs, .. }) => {
-                        assert!(substs.has_infer_types_or_consts());
 
-                        // FIXME: We only use the first inference variable we encounter in
-                        // `substs` here, this gives insufficiently informative diagnostics
-                        // in case there are multiple inference variables
-                        for s in substs.iter() {
-                            match s.unpack() {
-                                GenericArgKind::Type(t) => match t.kind() {
-                                    ty::Infer(_) => {
-                                        return self.extract_inference_diagnostics_data(s, None);
-                                    }
-                                    _ => {}
-                                },
-                                GenericArgKind::Const(c) => match c.val() {
-                                    ty::ConstKind::Infer(InferConst::Var(_)) => {
-                                        return self.extract_inference_diagnostics_data(s, None);
-                                    }
-                                    _ => {}
-                                },
-                                _ => {}
-                            }
-                        }
-                        bug!(
-                            "expected an inference variable in substs of unevaluated const {:?}",
-                            ct
-                        );
+                    debug_assert!(!origin.span.is_dummy());
+                    let mut printer = ty::print::FmtPrinter::new(self.tcx, Namespace::ValueNS);
+                    if let Some(highlight) = highlight {
+                        printer.region_highlight_mode = highlight;
                     }
-                    _ => {
-                        bug!("unexpect const: {:?}", ct);
+                    InferenceDiagnosticsData {
+                        name: ct.print(printer).unwrap().into_buffer(),
+                        span: Some(origin.span),
+                        kind: UnderspecifiedArgKind::Const { is_parameter: false },
+                        parent: None,
+                    }
+                } else {
+                    // If we end up here the `FindInferSourceVisitor`
+                    // won't work, as its expected argument isn't an inference variable.
+                    //
+                    // FIXME: Ideally we should look into the generic constant
+                    // to figure out which inference var is actually unresolved so that
+                    // this path is unreachable.
+                    let mut printer = ty::print::FmtPrinter::new(self.tcx, Namespace::ValueNS);
+                    if let Some(highlight) = highlight {
+                        printer.region_highlight_mode = highlight;
+                    }
+                    InferenceDiagnosticsData {
+                        name: ct.print(printer).unwrap().into_buffer(),
+                        span: None,
+                        kind: UnderspecifiedArgKind::Const { is_parameter: false },
+                        parent: None,
                     }
                 }
             }
@@ -480,457 +295,178 @@
         }
     }
 
+    /// Used as a fallback in [InferCtxt::emit_inference_failure_err]
+    /// in case we weren't able to get a better error.
+    fn bad_inference_failure_err(
+        &self,
+        span: Span,
+        arg_data: InferenceDiagnosticsData,
+        error_code: TypeAnnotationNeeded,
+    ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
+        let error_code = error_code.into();
+        let mut err =
+            self.tcx.sess.struct_span_err_with_code(span, "type annotations needed", error_code);
+        err.span_label(span, arg_data.cannot_infer_msg());
+        err
+    }
+
     pub fn emit_inference_failure_err(
         &self,
         body_id: Option<hir::BodyId>,
         span: Span,
         arg: GenericArg<'tcx>,
-        impl_candidates: Vec<ty::TraitRef<'tcx>>,
+        // FIXME(#94483): Either use this or remove it.
+        _impl_candidates: Vec<ty::TraitRef<'tcx>>,
         error_code: TypeAnnotationNeeded,
     ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
         let arg = self.resolve_vars_if_possible(arg);
         let arg_data = self.extract_inference_diagnostics_data(arg, None);
 
-        let mut local_visitor = FindHirNodeVisitor::new(&self, arg, span);
-        let ty_to_string = |ty: Ty<'tcx>| -> String {
-            let mut printer = ty::print::FmtPrinter::new(self.tcx, Namespace::TypeNS);
-            let ty_getter = move |ty_vid| {
-                if let TypeVariableOriginKind::TypeParameterDefinition(name, _) =
-                    self.inner.borrow_mut().type_variables().var_origin(ty_vid).kind
-                {
-                    Some(name.to_string())
-                } else {
-                    None
-                }
-            };
-            printer.ty_infer_name_resolver = Some(Box::new(ty_getter));
-            let const_getter = move |ct_vid| {
-                if let ConstVariableOriginKind::ConstParameterDefinition(name, _) = self
-                    .inner
-                    .borrow_mut()
-                    .const_unification_table()
-                    .probe_value(ct_vid)
-                    .origin
-                    .kind
-                {
-                    return Some(name.to_string());
-                } else {
-                    None
-                }
-            };
-            printer.const_infer_name_resolver = Some(Box::new(const_getter));
-
-            if let ty::FnDef(..) = ty.kind() {
-                // We don't want the regular output for `fn`s because it includes its path in
-                // invalid pseudo-syntax, we want the `fn`-pointer output instead.
-                ty.fn_sig(self.tcx).print(printer).unwrap().into_buffer()
-            } else {
-                ty.print(printer).unwrap().into_buffer()
-            }
+        let Some(typeck_results) = self.in_progress_typeck_results else {
+            // If we don't have any typeck results we're outside
+            // of a body, so we won't be able to get better info
+            // here.
+            return self.bad_inference_failure_err(span, arg_data, error_code);
         };
+        let typeck_results = typeck_results.borrow();
+        let typeck_results = &typeck_results;
 
+        let mut local_visitor = FindInferSourceVisitor::new(&self, typeck_results, arg);
         if let Some(body_id) = body_id {
             let expr = self.tcx.hir().expect_expr(body_id.hir_id);
+            debug!(?expr);
             local_visitor.visit_expr(expr);
         }
-        let err_span = if let Some(pattern) = local_visitor.found_arg_pattern {
-            pattern.span
-        } else if let Some(span) = arg_data.span {
-            // `span` here lets us point at `sum` instead of the entire right hand side expr:
-            // error[E0282]: type annotations needed
-            //  --> file2.rs:3:15
-            //   |
-            // 3 |     let _ = x.sum() as f64;
-            //   |               ^^^ cannot infer type for `S`
-            span
-        } else if let Some(ExprKind::MethodCall(segment, ..)) =
-            local_visitor.found_method_call.map(|e| &e.kind)
-        {
-            // Point at the call instead of the whole expression:
-            // error[E0284]: type annotations needed
-            //  --> file.rs:2:5
-            //   |
-            // 2 |     [Ok(2)].into_iter().collect()?;
-            //   |                         ^^^^^^^ cannot infer type
-            //   |
-            //   = note: cannot resolve `<_ as std::ops::Try>::Ok == _`
-            if span.contains(segment.ident.span) { segment.ident.span } else { span }
-        } else {
-            span
+
+        let Some(InferSource { span, kind }) = local_visitor.infer_source else {
+            return self.bad_inference_failure_err(span, arg_data, error_code)
         };
 
-        let is_named_and_not_impl_trait =
-            |ty: Ty<'_>| &ty.to_string() != "_" && !ty.is_impl_trait();
-
-        let ty_msg = match (local_visitor.found_node_ty, local_visitor.found_exact_method_call) {
-            (_, Some(_)) => String::new(),
-            (Some(ty), _) if ty.is_closure() => {
-                let ty::Closure(_, substs) = *ty.kind() else { unreachable!() };
-                let fn_sig = substs.as_closure().sig();
-                let args = closure_args(&fn_sig);
-                let ret = fn_sig.output().skip_binder().to_string();
-                format!(" for the closure `fn({}) -> {}`", args, ret)
-            }
-            (Some(ty), _) if is_named_and_not_impl_trait(ty) => {
-                let ty = ty_to_string(ty);
-                format!(" for `{}`", ty)
-            }
-            _ => String::new(),
-        };
-
-        // When `arg_data.name` corresponds to a type argument, show the path of the full type we're
-        // trying to infer. In the following example, `ty_msg` contains
-        // " for `std::result::Result<i32, E>`":
-        // ```
-        // error[E0282]: type annotations needed for `std::result::Result<i32, E>`
-        //  --> file.rs:L:CC
-        //   |
-        // L |     let b = Ok(4);
-        //   |         -   ^^ cannot infer type for `E` in `std::result::Result<i32, E>`
-        //   |         |
-        //   |         consider giving `b` the explicit type `std::result::Result<i32, E>`, where
-        //   |         the type parameter `E` is specified
-        // ```
         let error_code = error_code.into();
         let mut err = self.tcx.sess.struct_span_err_with_code(
-            err_span,
-            &format!("type annotations needed{}", ty_msg),
+            span,
+            &format!("type annotations needed{}", kind.ty_msg(self)),
             error_code,
         );
-
-        let use_diag = local_visitor.found_use_diagnostic.as_ref();
-        if let Some(use_diag) = use_diag && use_diag.applies_to(err_span) {
-            use_diag.attach_note(&mut err);
-        }
-
-        let param_type = arg_data.kind.descr();
-        let suffix = match local_visitor.found_node_ty {
-            Some(ty) if ty.is_closure() => {
-                let ty::Closure(_, substs) = *ty.kind() else { unreachable!() };
-                let fn_sig = substs.as_closure().sig();
-                let ret = fn_sig.output().skip_binder().to_string();
-
-                let closure_decl_and_body_id =
-                    local_visitor.found_closure.and_then(|closure| match &closure.kind {
-                        ExprKind::Closure(_, decl, body_id, ..) => Some((decl, *body_id)),
-                        _ => None,
-                    });
-
-                if let Some((decl, body_id)) = closure_decl_and_body_id {
-                    closure_return_type_suggestion(
-                        &mut err,
-                        &decl.output,
-                        self.tcx.hir().body(body_id),
-                        &ret,
-                    );
-                    // We don't want to give the other suggestions when the problem is the
-                    // closure return type.
-                    err.span_label(
-                        span,
-                        arg_data.cannot_infer_msg(use_diag.filter(|d| d.applies_to(span))),
-                    );
-                    return err;
-                }
-
-                // This shouldn't be reachable, but just in case we leave a reasonable fallback.
-                let args = closure_args(&fn_sig);
-                // This suggestion is incomplete, as the user will get further type inference
-                // errors due to the `_` placeholders and the introduction of `Box`, but it does
-                // nudge them in the right direction.
-                format!("a boxed closure type like `Box<dyn Fn({}) -> {}>`", args, ret)
-            }
-            Some(ty) if is_named_and_not_impl_trait(ty) && arg_data.name == "_" => {
-                let ty = ty_to_string(ty);
-                format!("the explicit type `{}`, with the {} parameters specified", ty, param_type)
-            }
-            Some(ty) if is_named_and_not_impl_trait(ty) && ty.to_string() != arg_data.name => {
-                let ty = ResolvedTypeParamEraser::new(self.tcx).fold_ty(ty);
-                let ty = ErrTypeParamEraser(self.tcx).fold_ty(ty);
-                let ty = ty_to_string(ty);
-                format!(
-                    "the explicit type `{}`, where the {} parameter `{}` is specified",
-                    ty, param_type, arg_data.name,
-                )
-            }
-            _ => "a type".to_string(),
-        };
-
-        if let Some(e) = local_visitor.found_exact_method_call {
-            if let ExprKind::MethodCall(segment, ..) = &e.kind {
-                // Suggest specifying type params or point out the return type of the call:
-                //
-                // error[E0282]: type annotations needed
-                //   --> $DIR/type-annotations-needed-expr.rs:2:39
-                //    |
-                // LL |     let _ = x.into_iter().sum() as f64;
-                //    |                           ^^^
-                //    |                           |
-                //    |                           cannot infer type for `S`
-                //    |                           help: consider specifying the type argument in
-                //    |                           the method call: `sum::<S>`
-                //    |
-                //    = note: type must be known at this point
-                //
-                // or
-                //
-                // error[E0282]: type annotations needed
-                //   --> $DIR/issue-65611.rs:59:20
-                //    |
-                // LL |     let x = buffer.last().unwrap().0.clone();
-                //    |             -------^^^^--
-                //    |             |      |
-                //    |             |      cannot infer type for `T`
-                //    |             this method call resolves to `std::option::Option<&T>`
-                //    |
-                //    = note: type must be known at this point
-                self.annotate_method_call(segment, e, &mut err);
-            }
-        } else if let Some(pattern) = local_visitor.found_arg_pattern {
-            // We don't want to show the default label for closures.
-            //
-            // So, before clearing, the output would look something like this:
-            // ```
-            // let x = |_| {  };
-            //          -  ^^^^ cannot infer type for `[_; 0]`
-            //          |
-            //          consider giving this closure parameter a type
-            // ```
-            //
-            // After clearing, it looks something like this:
-            // ```
-            // let x = |_| {  };
-            //          ^ consider giving this closure parameter the type `[_; 0]`
-            //            with the type parameter `_` specified
-            // ```
-            err.span_label(
-                pattern.span,
-                format!("consider giving this closure parameter {}", suffix),
-            );
-        } else if let Some(pattern) = local_visitor.found_local_pattern {
-            let msg = if let Some(simple_ident) = pattern.simple_ident() {
-                match pattern.span.desugaring_kind() {
-                    None => format!("consider giving `{}` {}", simple_ident, suffix),
-                    Some(_) => format!("this needs {}", suffix),
-                }
-            } else {
-                format!("consider giving this pattern {}", suffix)
-            };
-            err.span_label(pattern.span, msg);
-        } else if let Some(e) = local_visitor.found_method_call {
-            if let ExprKind::MethodCall(segment, exprs, _) = &e.kind {
-                // Suggest impl candidates:
-                //
-                // error[E0283]: type annotations needed
-                //   --> $DIR/E0283.rs:35:24
-                //    |
-                // LL |     let bar = foo_impl.into() * 1u32;
-                //    |               ---------^^^^--
-                //    |               |        |
-                //    |               |        cannot infer type for type parameter `T` declared on the trait `Into`
-                //    |               this method call resolves to `T`
-                //    |               help: specify type like: `<Impl as Into<u32>>::into(foo_impl)`
-                //    |
-                //    = note: cannot satisfy `Impl: Into<_>`
-                debug!(?segment);
-                if !impl_candidates.is_empty() && e.span.contains(span)
-                    && let Some(expr) = exprs.first()
-                    && let ExprKind::Path(hir::QPath::Resolved(_, path)) = expr.kind
-                    && let [_] = path.segments
-                {
-                    let mut eraser = TypeParamEraser(self.tcx);
-                    let candidate_len = impl_candidates.len();
-                    let mut suggestions: Vec<_> = impl_candidates.iter().filter_map(|candidate| {
-                        let trait_item = self.tcx
-                            .associated_items(candidate.def_id)
-                            .find_by_name_and_kind(
-                                self.tcx,
-                                segment.ident,
-                                ty::AssocKind::Fn,
-                                candidate.def_id
-                            );
-                        if trait_item.is_none() {
-                            return None;
-                        }
-                        let prefix = if let Some(trait_item) = trait_item
-                            && let Some(trait_m) = trait_item.def_id.as_local()
-                            && let hir::TraitItemKind::Fn(fn_, _) = &self.tcx.hir().trait_item(hir::TraitItemId { def_id: trait_m }).kind
-                        {
-                            match fn_.decl.implicit_self {
-                                hir::ImplicitSelfKind::ImmRef => "&",
-                                hir::ImplicitSelfKind::MutRef => "&mut ",
-                                _ => "",
-                            }
-                        } else {
-                            ""
-                        };
-                        let candidate = candidate.super_fold_with(&mut eraser);
-                        Some(vec![
-                            (expr.span.shrink_to_lo(), format!("{}::{}({}", candidate, segment.ident, prefix)),
-                            if exprs.len() == 1 {
-                                (expr.span.shrink_to_hi().with_hi(e.span.hi()), ")".to_string())
-                            } else {
-                                (expr.span.shrink_to_hi().with_hi(exprs[1].span.lo()), ", ".to_string())
-                            },
-                        ])
-                    }).collect();
-                    suggestions.sort_by(|a, b| a[0].1.cmp(&b[0].1));
-                    if !suggestions.is_empty() {
-                        err.multipart_suggestions(
-                            &format!(
-                                "use the fully qualified path for the potential candidate{}",
-                                pluralize!(candidate_len),
-                            ),
-                            suggestions.into_iter(),
-                            Applicability::MaybeIncorrect,
-                        );
-                    }
-                }
-                // Suggest specifying type params or point out the return type of the call:
-                //
-                // error[E0282]: type annotations needed
-                //   --> $DIR/type-annotations-needed-expr.rs:2:39
-                //    |
-                // LL |     let _ = x.into_iter().sum() as f64;
-                //    |                           ^^^
-                //    |                           |
-                //    |                           cannot infer type for `S`
-                //    |                           help: consider specifying the type argument in
-                //    |                           the method call: `sum::<S>`
-                //    |
-                //    = note: type must be known at this point
-                //
-                // or
-                //
-                // error[E0282]: type annotations needed
-                //   --> $DIR/issue-65611.rs:59:20
-                //    |
-                // LL |     let x = buffer.last().unwrap().0.clone();
-                //    |             -------^^^^--
-                //    |             |      |
-                //    |             |      cannot infer type for `T`
-                //    |             this method call resolves to `std::option::Option<&T>`
-                //    |
-                //    = note: type must be known at this point
-                self.annotate_method_call(segment, e, &mut err);
-            }
-        } else if let Some(scrutinee) = local_visitor.found_for_loop_iter {
-            err.span_label(
-                scrutinee.span,
-                "the element type for this iterator is not specified".to_string(),
-            );
-        }
-        // Instead of the following:
-        // error[E0282]: type annotations needed
-        //  --> file2.rs:3:15
-        //   |
-        // 3 |     let _ = x.sum() as f64;
-        //   |             --^^^--------- cannot infer type for `S`
-        //   |
-        //   = note: type must be known at this point
-        // We want:
-        // error[E0282]: type annotations needed
-        //  --> file2.rs:3:15
-        //   |
-        // 3 |     let _ = x.sum() as f64;
-        //   |               ^^^ cannot infer type for `S`
-        //   |
-        //   = note: type must be known at this point
-        let span = arg_data.span.unwrap_or(err_span);
-
-        // Avoid multiple labels pointing at `span`.
-        if !err
-            .span
-            .span_labels()
-            .iter()
-            .any(|span_label| span_label.label.is_some() && span_label.span == span)
-            && local_visitor.found_arg_pattern.is_none()
-        {
-            // FIXME(const_generics): we would like to handle const arguments
-            // as part of the normal diagnostics flow below, but there appear to
-            // be subtleties in doing so, so for now we special-case const args
-            // here.
-            if let (UnderspecifiedArgKind::Const { .. }, Some(parent_data)) =
-                (&arg_data.kind, &arg_data.parent)
-            {
-                // (#83606): Do not emit a suggestion if the parent has an `impl Trait`
-                // as an argument otherwise it will cause the E0282 error.
-                if !self.tcx.generics_of(parent_data.def_id).has_impl_trait()
-                    || self.tcx.features().explicit_generic_args_with_impl_trait
-                {
-                    err.span_suggestion_verbose(
-                        span,
-                        "consider specifying the const argument",
-                        format!("{}::<{}>", parent_data.name, arg_data.name),
-                        Applicability::MaybeIncorrect,
-                    );
-                }
-            }
-
-            err.span_label(
-                span,
-                arg_data.cannot_infer_msg(use_diag.filter(|d| d.applies_to(span))),
-            );
-        }
-
-        err
-    }
-
-    fn trait_def_from_hir_fn(&self, hir_id: hir::HirId) -> Option<DefId> {
-        // The DefId will be the method's trait item ID unless this is an inherent impl
-        if let Some((DefKind::AssocFn, def_id)) =
-            self.in_progress_typeck_results?.borrow().type_dependent_def(hir_id)
-        {
-            let parent_def_id = self.tcx.parent(def_id);
-            return self.tcx.is_trait(parent_def_id).then_some(parent_def_id);
-        }
-
-        None
-    }
-
-    /// If the `FnSig` for the method call can be found and type arguments are identified as
-    /// needed, suggest annotating the call, otherwise point out the resulting type of the call.
-    fn annotate_method_call(
-        &self,
-        segment: &hir::PathSegment<'_>,
-        e: &Expr<'_>,
-        err: &mut Diagnostic,
-    ) {
-        if let (Some(typeck_results), None) = (self.in_progress_typeck_results, &segment.args) {
-            let borrow = typeck_results.borrow();
-            if let Some((DefKind::AssocFn, did)) = borrow.type_dependent_def(e.hir_id) {
-                let generics = self.tcx.generics_of(did);
-                if !generics.params.is_empty() && !generics.has_impl_trait() {
-                    err.span_suggestion_verbose(
-                        segment.ident.span.shrink_to_hi(),
-                        &format!(
-                            "consider specifying the type argument{} in the method call",
-                            pluralize!(generics.params.len()),
-                        ),
-                        format!(
-                            "::<{}>",
-                            generics
-                                .params
-                                .iter()
-                                .map(|p| p.name.to_string())
-                                .collect::<Vec<String>>()
-                                .join(", ")
-                        ),
-                        Applicability::HasPlaceholders,
-                    );
+        match kind {
+            InferSourceKind::LetBinding { insert_span, pattern_name, ty } => {
+                let suggestion_msg = if let Some(name) = pattern_name {
+                    format!(
+                        "consider giving `{}` an explicit type{}",
+                        name,
+                        arg_data.where_x_is_specified(ty)
+                    )
                 } else {
-                    let sig = self.tcx.fn_sig(did);
-                    let bound_output = sig.output();
-                    let output = bound_output.skip_binder();
-                    err.span_label(e.span, &format!("this method call resolves to `{}`", output));
-                    let kind = output.kind();
-                    if let ty::Projection(proj) = kind {
-                        if let Some(span) = self.tcx.hir().span_if_local(proj.item_def_id) {
-                            err.span_label(span, &format!("`{}` defined here", output));
-                        }
-                    }
-                }
+                    format!(
+                        "consider giving this pattern a type{}",
+                        arg_data.where_x_is_specified(ty)
+                    )
+                };
+                err.span_suggestion_verbose(
+                    insert_span,
+                    &suggestion_msg,
+                    format!(": {}", ty_to_string(self, ty)),
+                    Applicability::HasPlaceholders,
+                );
+            }
+            InferSourceKind::ClosureArg { insert_span, ty } => {
+                err.span_suggestion_verbose(
+                    insert_span,
+                    &format!(
+                        "consider giving this closure parameter an explicit type{}",
+                        arg_data.where_x_is_specified(ty)
+                    ),
+                    format!(": {}", ty_to_string(self, ty)),
+                    Applicability::HasPlaceholders,
+                );
+            }
+            InferSourceKind::GenericArg {
+                insert_span,
+                argument_index,
+                generics_def_id,
+                def_id: _,
+                generic_args,
+            } => {
+                let generics = self.tcx.generics_of(generics_def_id);
+                let is_type = matches!(arg.unpack(), GenericArgKind::Type(_));
+
+                let cannot_infer_msg = format!(
+                    "cannot infer {} of the {} parameter `{}`{}",
+                    if is_type { "type" } else { "the value" },
+                    if is_type { "type" } else { "const" },
+                    generics.params[argument_index].name,
+                    // We use the `generics_def_id` here, as even when suggesting `None::<T>`,
+                    // the type parameter `T` was still declared on the enum, not on the
+                    // variant.
+                    InferenceDiagnosticsParentData::for_parent_def_id(self.tcx, generics_def_id)
+                        .map_or(String::new(), |parent| parent.suffix_string()),
+                );
+
+                err.span_label(span, cannot_infer_msg);
+
+                let printer = fmt_printer(self, Namespace::TypeNS);
+                let args = printer.comma_sep(generic_args.iter().copied()).unwrap().into_buffer();
+                err.span_suggestion_verbose(
+                    insert_span,
+                    &format!("consider specifying the generic argument{}", pluralize!(args.len()),),
+                    format!("::<{}>", args),
+                    Applicability::HasPlaceholders,
+                );
+            }
+            InferSourceKind::FullyQualifiedMethodCall { receiver, successor, substs, def_id } => {
+                let printer = fmt_printer(self, Namespace::ValueNS);
+                let def_path = printer.print_def_path(def_id, substs).unwrap().into_buffer();
+
+                // We only care about whether we have to add `&` or `&mut ` for now.
+                // This is the case if the last adjustment is a borrow and the
+                // first adjustment was not a builtin deref.
+                let adjustment = match typeck_results.expr_adjustments(receiver) {
+                    [
+                        Adjustment { kind: Adjust::Deref(None), target: _ },
+                        ..,
+                        Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(..)), target: _ },
+                    ] => "",
+                    [
+                        ..,
+                        Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(_, mut_)), target: _ },
+                    ] => match mut_ {
+                        AutoBorrowMutability::Mut { .. } => "&mut ",
+                        AutoBorrowMutability::Not => "&",
+                    },
+                    _ => "",
+                };
+
+                let suggestion = vec![
+                    (receiver.span.shrink_to_lo(), format!("{def_path}({adjustment}")),
+                    (receiver.span.shrink_to_hi().with_hi(successor.1), successor.0.to_string()),
+                ];
+                err.multipart_suggestion_verbose(
+                    "try using a fully qualified path to specify the expected types",
+                    suggestion,
+                    Applicability::HasPlaceholders,
+                );
+            }
+            InferSourceKind::ClosureReturn { ty, data, should_wrap_expr } => {
+                let ret = ty_to_string(self, ty);
+                let (arrow, post) = match data {
+                    FnRetTy::DefaultReturn(_) => ("-> ", " "),
+                    _ => ("", ""),
+                };
+                let suggestion = match should_wrap_expr {
+                    Some(end_span) => vec![
+                        (data.span(), format!("{}{}{}{{ ", arrow, ret, post)),
+                        (end_span, " }".to_string()),
+                    ],
+                    None => vec![(data.span(), format!("{}{}{}", arrow, ret, post))],
+                };
+                err.multipart_suggestion_verbose(
+                    "try giving this closure an explicit return type",
+                    suggestion,
+                    Applicability::HasPlaceholders,
+                );
             }
         }
+        err
     }
 
     pub fn need_type_info_err_in_generator(
@@ -949,136 +485,559 @@
             "type inside {} must be known in this context",
             kind,
         );
-        err.span_label(span, data.cannot_infer_msg(None));
+        err.span_label(span, data.cannot_infer_msg());
         err
     }
 }
 
-/// Turn *resolved* type params into `[type error]` to signal we don't want to display them. After
-/// performing that replacement, we'll turn all remaining infer type params to use their name from
-/// their definition, and replace all the `[type error]`s back to being infer so they display in
-/// the output as `_`. If we didn't go through `[type error]`, we would either show all type params
-/// by their name *or* `_`, neither of which is desirable: we want to show all types that we could
-/// infer as `_` to reduce verbosity and avoid telling the user about unnecessary type annotations.
-struct ResolvedTypeParamEraser<'tcx> {
-    tcx: TyCtxt<'tcx>,
-    level: usize,
+#[derive(Debug)]
+struct InferSource<'tcx> {
+    span: Span,
+    kind: InferSourceKind<'tcx>,
 }
 
-impl<'tcx> ResolvedTypeParamEraser<'tcx> {
-    fn new(tcx: TyCtxt<'tcx>) -> Self {
-        ResolvedTypeParamEraser { tcx, level: 0 }
-    }
-
-    /// Replace not yet inferred const params with their def name.
-    fn replace_infers(&self, c: Const<'tcx>, index: u32, name: Symbol) -> Const<'tcx> {
-        match c.val() {
-            ty::ConstKind::Infer(..) => self.tcx().mk_const_param(index, name, c.ty()),
-            _ => c,
-        }
-    }
+#[derive(Debug)]
+enum InferSourceKind<'tcx> {
+    LetBinding {
+        insert_span: Span,
+        pattern_name: Option<Ident>,
+        ty: Ty<'tcx>,
+    },
+    ClosureArg {
+        insert_span: Span,
+        ty: Ty<'tcx>,
+    },
+    GenericArg {
+        insert_span: Span,
+        argument_index: usize,
+        generics_def_id: DefId,
+        def_id: DefId,
+        generic_args: &'tcx [GenericArg<'tcx>],
+    },
+    FullyQualifiedMethodCall {
+        receiver: &'tcx Expr<'tcx>,
+        /// If the method has other arguments, this is ", " and the start of the first argument,
+        /// while for methods without arguments this is ")" and the end of the method call.
+        successor: (&'static str, BytePos),
+        substs: SubstsRef<'tcx>,
+        def_id: DefId,
+    },
+    ClosureReturn {
+        ty: Ty<'tcx>,
+        data: &'tcx FnRetTy<'tcx>,
+        should_wrap_expr: Option<Span>,
+    },
 }
 
-impl<'tcx> TypeFolder<'tcx> for ResolvedTypeParamEraser<'tcx> {
-    fn tcx<'a>(&'a self) -> TyCtxt<'tcx> {
-        self.tcx
-    }
-    fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
-        self.level += 1;
-        let t = match t.kind() {
-            // We'll hide this type only if all its type params are hidden as well.
-            ty::Adt(def, substs) => {
-                let generics = self.tcx().generics_of(def.did());
-                // Account for params with default values, like `Vec`, where we
-                // want to show `Vec<T>`, not `Vec<T, _>`. If we replaced that
-                // subst, then we'd get the incorrect output, so we passthrough.
-                let substs: Vec<_> = substs
-                    .iter()
-                    .zip(generics.params.iter())
-                    .map(|(subst, param)| match &(subst.unpack(), &param.kind) {
-                        (_, ty::GenericParamDefKind::Type { has_default: true, .. }) => subst,
-                        (crate::infer::GenericArgKind::Const(c), _) => {
-                            self.replace_infers(*c, param.index, param.name).into()
-                        }
-                        _ => subst.super_fold_with(self),
-                    })
-                    .collect();
-                let should_keep = |subst: &GenericArg<'_>| match subst.unpack() {
-                    ty::subst::GenericArgKind::Type(t) => match t.kind() {
-                        ty::Error(_) => false,
-                        _ => true,
-                    },
-                    // Account for `const` params here, otherwise `doesnt_infer.rs`
-                    // shows `_` instead of `Foo<{ _: u32 }>`
-                    ty::subst::GenericArgKind::Const(_) => true,
-                    _ => false,
-                };
-                if self.level == 1 || substs.iter().any(should_keep) {
-                    let substs = self.tcx().intern_substs(&substs[..]);
-                    self.tcx().mk_ty(ty::Adt(*def, substs))
+impl<'tcx> InferSourceKind<'tcx> {
+    fn ty_msg(&self, infcx: &InferCtxt<'_, 'tcx>) -> String {
+        match *self {
+            InferSourceKind::LetBinding { ty, .. }
+            | InferSourceKind::ClosureArg { ty, .. }
+            | InferSourceKind::ClosureReturn { ty, .. } => {
+                if ty.is_closure() {
+                    format!(" for the closure `{}`", closure_as_fn_str(infcx, ty))
+                } else if !ty.is_ty_infer() {
+                    format!(" for `{}`", ty_to_string(infcx, ty))
                 } else {
-                    self.tcx().ty_error()
+                    String::new()
                 }
             }
-            ty::Ref(_, ty, _) => {
-                let ty = self.fold_ty(*ty);
-                match ty.kind() {
-                    // Avoid `&_`, these can be safely presented as `_`.
-                    ty::Error(_) => self.tcx().ty_error(),
-                    _ => t.super_fold_with(self),
-                }
-            }
-            // We could account for `()` if we wanted to replace it, but it's assured to be short.
-            ty::Tuple(_)
-            | ty::Slice(_)
-            | ty::RawPtr(_)
-            | ty::FnDef(..)
-            | ty::FnPtr(_)
-            | ty::Opaque(..)
-            | ty::Projection(_)
-            | ty::Never => t.super_fold_with(self),
-            ty::Array(ty, c) => {
-                self.tcx().mk_ty(ty::Array(self.fold_ty(*ty), self.replace_infers(*c, 0, sym::N)))
-            }
-            // We don't want to hide type params that haven't been resolved yet.
-            // This would be the type that will be written out with the type param
-            // name in the output.
-            ty::Infer(_) => t,
-            // We don't want to hide the outermost type, only its type params.
-            _ if self.level == 1 => t.super_fold_with(self),
-            // Hide this type
-            _ => self.tcx().ty_error(),
-        };
-        self.level -= 1;
-        t
-    }
-}
-
-/// Replace `[type error]` with `ty::Infer(ty::Var)` to display `_`.
-struct ErrTypeParamEraser<'tcx>(TyCtxt<'tcx>);
-impl<'tcx> TypeFolder<'tcx> for ErrTypeParamEraser<'tcx> {
-    fn tcx<'a>(&'a self) -> TyCtxt<'tcx> {
-        self.0
-    }
-    fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
-        match t.kind() {
-            ty::Error(_) => self.tcx().mk_ty_var(ty::TyVid::from_u32(0)),
-            _ => t.super_fold_with(self),
+            // FIXME: We should be able to add some additional info here.
+            InferSourceKind::GenericArg { .. }
+            | InferSourceKind::FullyQualifiedMethodCall { .. } => String::new(),
         }
     }
 }
 
-/// Replace type parameters with `ty::Infer(ty::Var)` to display `_`.
-struct TypeParamEraser<'tcx>(TyCtxt<'tcx>);
+struct InsertableGenericArgs<'tcx> {
+    insert_span: Span,
+    substs: SubstsRef<'tcx>,
+    generics_def_id: DefId,
+    def_id: DefId,
+}
 
-impl<'tcx> TypeFolder<'tcx> for TypeParamEraser<'tcx> {
-    fn tcx<'a>(&'a self) -> TyCtxt<'tcx> {
-        self.0
+/// A visitor which searches for the "best" spot to use in the inference error.
+///
+/// For this it walks over the hir body and tries to check all places where
+/// inference variables could be bound.
+///
+/// While doing so, the currently best spot is stored in `infer_source`.
+/// For details on how we rank spots, see [Self::source_cost]
+struct FindInferSourceVisitor<'a, 'tcx> {
+    infcx: &'a InferCtxt<'a, 'tcx>,
+    typeck_results: &'a TypeckResults<'tcx>,
+
+    target: GenericArg<'tcx>,
+
+    attempt: usize,
+    infer_source_cost: usize,
+    infer_source: Option<InferSource<'tcx>>,
+}
+
+impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
+    fn new(
+        infcx: &'a InferCtxt<'a, 'tcx>,
+        typeck_results: &'a TypeckResults<'tcx>,
+        target: GenericArg<'tcx>,
+    ) -> Self {
+        FindInferSourceVisitor {
+            infcx,
+            typeck_results,
+
+            target,
+
+            attempt: 0,
+            infer_source_cost: usize::MAX,
+            infer_source: None,
+        }
     }
-    fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
-        match t.kind() {
-            ty::Param(_) | ty::Error(_) => self.tcx().mk_ty_var(ty::TyVid::from_u32(0)),
-            _ => t.super_fold_with(self),
+
+    /// Computes cost for the given source.
+    ///
+    /// Sources with a small cost are prefer and should result
+    /// in a clearer and idiomatic suggestion.
+    fn source_cost(&self, source: &InferSource<'tcx>) -> usize {
+        let tcx = self.infcx.tcx;
+
+        fn arg_cost<'tcx>(arg: GenericArg<'tcx>) -> usize {
+            match arg.unpack() {
+                GenericArgKind::Lifetime(_) => 0, // erased
+                GenericArgKind::Type(ty) => ty_cost(ty),
+                GenericArgKind::Const(_) => 3, // some non-zero value
+            }
+        }
+        fn ty_cost<'tcx>(ty: Ty<'tcx>) -> usize {
+            match ty.kind() {
+                ty::Closure(..) => 100,
+                ty::FnDef(..) => 20,
+                ty::FnPtr(..) => 10,
+                ty::Infer(..) => 0,
+                _ => 1,
+            }
+        }
+
+        // The sources are listed in order of preference here.
+        match source.kind {
+            InferSourceKind::LetBinding { ty, .. } => ty_cost(ty),
+            InferSourceKind::ClosureArg { ty, .. } => 5 + ty_cost(ty),
+            InferSourceKind::GenericArg { def_id, generic_args, .. } => {
+                let variant_cost = match tcx.def_kind(def_id) {
+                    DefKind::Variant | DefKind::Ctor(CtorOf::Variant, _) => 15, // `None::<u32>` and friends are ugly.
+                    _ => 12,
+                };
+                variant_cost + generic_args.iter().map(|&arg| arg_cost(arg)).sum::<usize>()
+            }
+            InferSourceKind::FullyQualifiedMethodCall { substs, .. } => {
+                20 + substs.iter().map(|arg| arg_cost(arg)).sum::<usize>()
+            }
+            InferSourceKind::ClosureReturn { ty, should_wrap_expr, .. } => {
+                30 + ty_cost(ty) + if should_wrap_expr.is_some() { 10 } else { 0 }
+            }
+        }
+    }
+
+    /// Uses `fn source_cost` to determine whether this inference source is preferable to
+    /// previous sources. We generally prefer earlier sources.
+    #[instrument(level = "debug", skip(self))]
+    fn update_infer_source(&mut self, new_source: InferSource<'tcx>) {
+        let cost = self.source_cost(&new_source) + self.attempt;
+        self.attempt += 1;
+        if cost < self.infer_source_cost {
+            self.infer_source_cost = cost;
+            self.infer_source = Some(new_source);
+        }
+    }
+
+    fn opt_node_type(&self, hir_id: HirId) -> Option<Ty<'tcx>> {
+        let ty = self.typeck_results.node_type_opt(hir_id);
+        self.infcx.resolve_vars_if_possible(ty)
+    }
+
+    // Check whether this generic argument is the inference variable we
+    // are looking for.
+    fn generic_arg_is_target(&self, arg: GenericArg<'tcx>) -> bool {
+        if arg == self.target {
+            return true;
+        }
+
+        match (arg.unpack(), self.target.unpack()) {
+            (GenericArgKind::Type(inner_ty), GenericArgKind::Type(target_ty)) => {
+                use ty::{Infer, TyVar};
+                match (inner_ty.kind(), target_ty.kind()) {
+                    (&Infer(TyVar(a_vid)), &Infer(TyVar(b_vid))) => {
+                        self.infcx.inner.borrow_mut().type_variables().sub_unified(a_vid, b_vid)
+                    }
+                    _ => false,
+                }
+            }
+            (GenericArgKind::Const(inner_ct), GenericArgKind::Const(target_ct)) => {
+                use ty::InferConst::*;
+                match (inner_ct.kind(), target_ct.kind()) {
+                    (ty::ConstKind::Infer(Var(a_vid)), ty::ConstKind::Infer(Var(b_vid))) => self
+                        .infcx
+                        .inner
+                        .borrow_mut()
+                        .const_unification_table()
+                        .unioned(a_vid, b_vid),
+                    _ => false,
+                }
+            }
+            _ => false,
+        }
+    }
+
+    /// Does this generic argument contain our target inference variable
+    /// in a way which can be written by the user.
+    fn generic_arg_contains_target(&self, arg: GenericArg<'tcx>) -> bool {
+        let mut walker = arg.walk();
+        while let Some(inner) = walker.next() {
+            if self.generic_arg_is_target(inner) {
+                return true;
+            }
+            match inner.unpack() {
+                GenericArgKind::Lifetime(_) => {}
+                GenericArgKind::Type(ty) => {
+                    if matches!(ty.kind(), ty::Opaque(..) | ty::Closure(..) | ty::Generator(..)) {
+                        // Opaque types can't be named by the user right now.
+                        //
+                        // Both the generic arguments of closures and generators can
+                        // also not be named. We may want to only look into the closure
+                        // signature in case it has no captures, as that can be represented
+                        // using `fn(T) -> R`.
+
+                        // FIXME(type_alias_impl_trait): These opaque types
+                        // can actually be named, so it would make sense to
+                        // adjust this case and add a test for it.
+                        walker.skip_current_subtree();
+                    }
+                }
+                GenericArgKind::Const(ct) => {
+                    if matches!(ct.kind(), ty::ConstKind::Unevaluated(..)) {
+                        // You can't write the generic arguments for
+                        // unevaluated constants.
+                        walker.skip_current_subtree();
+                    }
+                }
+            }
+        }
+        false
+    }
+
+    fn expr_inferred_subst_iter(
+        &self,
+        expr: &'tcx hir::Expr<'tcx>,
+    ) -> Box<dyn Iterator<Item = InsertableGenericArgs<'tcx>> + 'a> {
+        let tcx = self.infcx.tcx;
+        match expr.kind {
+            hir::ExprKind::Path(ref path) => {
+                if let Some(substs) = self.typeck_results.node_substs_opt(expr.hir_id) {
+                    return self.path_inferred_subst_iter(expr.hir_id, substs, path);
+                }
+            }
+            hir::ExprKind::Struct(path, _, _) => {
+                if let Some(ty) = self.opt_node_type(expr.hir_id) {
+                    if let ty::Adt(_, substs) = ty.kind() {
+                        return self.path_inferred_subst_iter(expr.hir_id, substs, path);
+                    }
+                }
+            }
+            hir::ExprKind::MethodCall(segment, _, _) => {
+                if let Some(def_id) = self.typeck_results.type_dependent_def_id(expr.hir_id) {
+                    let generics = tcx.generics_of(def_id);
+                    let insertable: Option<_> = try {
+                        if generics.has_impl_trait() {
+                            None?
+                        }
+                        let substs = self.typeck_results.node_substs_opt(expr.hir_id)?;
+                        let span = tcx.hir().span(segment.hir_id?);
+                        let insert_span = segment.ident.span.shrink_to_hi().with_hi(span.hi());
+                        InsertableGenericArgs {
+                            insert_span,
+                            substs,
+                            generics_def_id: def_id,
+                            def_id,
+                        }
+                    };
+                    return Box::new(insertable.into_iter());
+                }
+            }
+            _ => {}
+        }
+
+        Box::new(iter::empty())
+    }
+
+    fn resolved_path_inferred_subst_iter(
+        &self,
+        path: &'tcx hir::Path<'tcx>,
+        substs: SubstsRef<'tcx>,
+    ) -> impl Iterator<Item = InsertableGenericArgs<'tcx>> + 'a {
+        let tcx = self.infcx.tcx;
+        // The last segment of a path often has `Res::Err` and the
+        // correct `Res` is the one of the whole path.
+        //
+        // FIXME: We deal with that one separately for now,
+        // would be good to remove this special case.
+        let last_segment_using_path_data: Option<_> = try {
+            let generics_def_id = tcx.res_generics_def_id(path.res)?;
+            let generics = tcx.generics_of(generics_def_id);
+            if generics.has_impl_trait() {
+                None?
+            }
+            let insert_span =
+                path.segments.last().unwrap().ident.span.shrink_to_hi().with_hi(path.span.hi());
+            InsertableGenericArgs {
+                insert_span,
+                substs,
+                generics_def_id,
+                def_id: path.res.def_id(),
+            }
+        };
+
+        path.segments
+            .iter()
+            .filter_map(move |segment| {
+                let res = segment.res?;
+                let generics_def_id = tcx.res_generics_def_id(res)?;
+                let generics = tcx.generics_of(generics_def_id);
+                if generics.has_impl_trait() {
+                    return None;
+                }
+                let span = tcx.hir().span(segment.hir_id?);
+                let insert_span = segment.ident.span.shrink_to_hi().with_hi(span.hi());
+                Some(InsertableGenericArgs {
+                    insert_span,
+                    substs,
+                    generics_def_id,
+                    def_id: res.def_id(),
+                })
+            })
+            .chain(last_segment_using_path_data)
+    }
+
+    fn path_inferred_subst_iter(
+        &self,
+        hir_id: HirId,
+        substs: SubstsRef<'tcx>,
+        qpath: &'tcx hir::QPath<'tcx>,
+    ) -> Box<dyn Iterator<Item = InsertableGenericArgs<'tcx>> + 'a> {
+        let tcx = self.infcx.tcx;
+        match qpath {
+            hir::QPath::Resolved(_self_ty, path) => {
+                Box::new(self.resolved_path_inferred_subst_iter(path, substs))
+            }
+            hir::QPath::TypeRelative(ty, segment) => {
+                let Some(def_id) = self.typeck_results.type_dependent_def_id(hir_id) else {
+                    return Box::new(iter::empty());
+                };
+
+                let generics = tcx.generics_of(def_id);
+                let segment: Option<_> = try {
+                    if !segment.infer_args || generics.has_impl_trait() {
+                        None?;
+                    }
+                    let span = tcx.hir().span(segment.hir_id?);
+                    let insert_span = segment.ident.span.shrink_to_hi().with_hi(span.hi());
+                    InsertableGenericArgs { insert_span, substs, generics_def_id: def_id, def_id }
+                };
+
+                let parent_def_id = generics.parent.unwrap();
+                if tcx.def_kind(parent_def_id) == DefKind::Impl {
+                    let parent_ty = tcx.bound_type_of(parent_def_id).subst(tcx, substs);
+                    match (parent_ty.kind(), &ty.kind) {
+                        (
+                            ty::Adt(def, substs),
+                            hir::TyKind::Path(hir::QPath::Resolved(_self_ty, path)),
+                        ) => {
+                            if tcx.res_generics_def_id(path.res) != Some(def.did()) {
+                                match path.res {
+                                    Res::Def(DefKind::TyAlias, _) => {
+                                        // FIXME: Ideally we should support this. For that
+                                        // we have to map back from the self type to the
+                                        // type alias though. That's difficult.
+                                        //
+                                        // See the `need_type_info/type-alias.rs` test for
+                                        // some examples.
+                                    }
+                                    // There cannot be inference variables in the self type,
+                                    // so there's nothing for us to do here.
+                                    Res::SelfTy { .. } => {}
+                                    _ => warn!(
+                                        "unexpected path: def={:?} substs={:?} path={:?}",
+                                        def, substs, path,
+                                    ),
+                                }
+                            } else {
+                                return Box::new(
+                                    self.resolved_path_inferred_subst_iter(path, substs)
+                                        .chain(segment),
+                                );
+                            }
+                        }
+                        _ => (),
+                    }
+                }
+
+                Box::new(segment.into_iter())
+            }
+            hir::QPath::LangItem(_, _, _) => Box::new(iter::empty()),
+        }
+    }
+}
+
+impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> {
+    type NestedFilter = nested_filter::OnlyBodies;
+
+    fn nested_visit_map(&mut self) -> Self::Map {
+        self.infcx.tcx.hir()
+    }
+
+    fn visit_local(&mut self, local: &'tcx Local<'tcx>) {
+        intravisit::walk_local(self, local);
+
+        if let Some(ty) = self.opt_node_type(local.hir_id) {
+            if self.generic_arg_contains_target(ty.into()) {
+                match local.source {
+                    LocalSource::Normal if local.ty.is_none() => {
+                        self.update_infer_source(InferSource {
+                            span: local.pat.span,
+                            kind: InferSourceKind::LetBinding {
+                                insert_span: local.pat.span.shrink_to_hi(),
+                                pattern_name: local.pat.simple_ident(),
+                                ty,
+                            },
+                        })
+                    }
+                    _ => {}
+                }
+            }
+        }
+    }
+
+    /// For closures, we first visit the parameters and then the content,
+    /// as we prefer those.
+    fn visit_body(&mut self, body: &'tcx Body<'tcx>) {
+        for param in body.params {
+            debug!(
+                "param: span {:?}, ty_span {:?}, pat.span {:?}",
+                param.span, param.ty_span, param.pat.span
+            );
+            if param.ty_span != param.pat.span {
+                debug!("skipping param: has explicit type");
+                continue;
+            }
+
+            let Some(param_ty) = self.opt_node_type(param.hir_id) else {
+                continue
+            };
+
+            if self.generic_arg_contains_target(param_ty.into()) {
+                self.update_infer_source(InferSource {
+                    span: param.pat.span,
+                    kind: InferSourceKind::ClosureArg {
+                        insert_span: param.pat.span.shrink_to_hi(),
+                        ty: param_ty,
+                    },
+                })
+            }
+        }
+        intravisit::walk_body(self, body);
+    }
+
+    fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
+        let tcx = self.infcx.tcx;
+        match expr.kind {
+            // When encountering `func(arg)` first look into `arg` and then `func`,
+            // as `arg` is "more specific".
+            ExprKind::Call(func, args) => {
+                for arg in args {
+                    self.visit_expr(arg);
+                }
+                self.visit_expr(func);
+            }
+            _ => intravisit::walk_expr(self, expr),
+        }
+
+        for InsertableGenericArgs { insert_span, substs, generics_def_id, def_id } in
+            self.expr_inferred_subst_iter(expr)
+        {
+            let generics = tcx.generics_of(generics_def_id);
+            if let Some(argument_index) =
+                generics.own_substs(substs).iter().position(|&arg| self.generic_arg_is_target(arg))
+            {
+                let substs = self.infcx.resolve_vars_if_possible(substs);
+                let generic_args = &generics.own_substs_no_defaults(tcx, substs)
+                    [generics.own_counts().lifetimes..];
+                let span = match expr.kind {
+                    ExprKind::MethodCall(path, _, _) => path.ident.span,
+                    _ => expr.span,
+                };
+
+                self.update_infer_source(InferSource {
+                    span,
+                    kind: InferSourceKind::GenericArg {
+                        insert_span,
+                        argument_index,
+                        generics_def_id,
+                        def_id,
+                        generic_args,
+                    },
+                });
+            }
+        }
+
+        if let Some(node_ty) = self.opt_node_type(expr.hir_id) {
+            if let (
+                &ExprKind::Closure { fn_decl, body, fn_decl_span, .. },
+                ty::Closure(_, substs),
+            ) = (&expr.kind, node_ty.kind())
+            {
+                let output = substs.as_closure().sig().output().skip_binder();
+                if self.generic_arg_contains_target(output.into()) {
+                    let body = self.infcx.tcx.hir().body(body);
+                    let should_wrap_expr = if matches!(body.value.kind, ExprKind::Block(..)) {
+                        None
+                    } else {
+                        Some(body.value.span.shrink_to_hi())
+                    };
+                    self.update_infer_source(InferSource {
+                        span: fn_decl_span,
+                        kind: InferSourceKind::ClosureReturn {
+                            ty: output,
+                            data: &fn_decl.output,
+                            should_wrap_expr,
+                        },
+                    })
+                }
+            }
+        }
+
+        let has_impl_trait = |def_id| {
+            iter::successors(Some(tcx.generics_of(def_id)), |generics| {
+                generics.parent.map(|def_id| tcx.generics_of(def_id))
+            })
+            .any(|generics| generics.has_impl_trait())
+        };
+        if let ExprKind::MethodCall(path, args, span) = expr.kind
+            && let Some(substs) = self.typeck_results.node_substs_opt(expr.hir_id)
+            && substs.iter().any(|arg| self.generic_arg_contains_target(arg))
+            && let Some(def_id) = self.typeck_results.type_dependent_def_id(expr.hir_id)
+            && self.infcx.tcx.trait_of_item(def_id).is_some()
+            && !has_impl_trait(def_id)
+        {
+            let successor =
+                args.get(1).map_or_else(|| (")", span.hi()), |arg| (", ", arg.span.lo()));
+            let substs = self.infcx.resolve_vars_if_possible(substs);
+            self.update_infer_source(InferSource {
+                span: path.ident.span,
+                kind: InferSourceKind::FullyQualifiedMethodCall {
+                    receiver: args.first().unwrap(),
+                    successor,
+                    substs,
+                    def_id,
+                }
+            })
         }
     }
 }
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs
index cb72cb4..b744594 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs
@@ -12,6 +12,7 @@
 use rustc_hir as hir;
 use rustc_hir::{GenericParamKind, Ty};
 use rustc_middle::ty::Region;
+use rustc_span::symbol::kw;
 
 impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
     /// Print the error message for lifetime errors when both the concerned regions are anonymous.
@@ -169,7 +170,7 @@
         return false;
     };
 
-    if !lifetime_sub.name.is_elided() || !lifetime_sup.name.is_elided() {
+    if !lifetime_sub.name.is_anonymous() || !lifetime_sup.name.is_anonymous() {
         return false;
     };
 
@@ -188,32 +189,37 @@
         _ => return false,
     };
 
-    let (suggestion_param_name, introduce_new) = generics
+    let suggestion_param_name = generics
         .params
         .iter()
-        .find(|p| matches!(p.kind, GenericParamKind::Lifetime { .. }))
-        .and_then(|p| tcx.sess.source_map().span_to_snippet(p.span).ok())
-        .map(|name| (name, false))
-        .unwrap_or_else(|| ("'a".to_string(), true));
+        .filter(|p| matches!(p.kind, GenericParamKind::Lifetime { .. }))
+        .map(|p| p.name.ident().name)
+        .find(|i| *i != kw::UnderscoreLifetime);
+    let introduce_new = suggestion_param_name.is_none();
+    let suggestion_param_name =
+        suggestion_param_name.map(|n| n.to_string()).unwrap_or_else(|| "'a".to_owned());
 
-    let mut suggestions = vec![
-        if let hir::LifetimeName::Underscore = lifetime_sub.name {
-            (lifetime_sub.span, suggestion_param_name.clone())
+    debug!(?lifetime_sup.span);
+    debug!(?lifetime_sub.span);
+    let make_suggestion = |span: rustc_span::Span| {
+        if span.is_empty() {
+            (span, format!("{}, ", suggestion_param_name))
+        } else if let Ok("&") = tcx.sess.source_map().span_to_snippet(span).as_deref() {
+            (span.shrink_to_hi(), format!("{} ", suggestion_param_name))
         } else {
-            (lifetime_sub.span.shrink_to_hi(), suggestion_param_name.clone() + " ")
-        },
-        if let hir::LifetimeName::Underscore = lifetime_sup.name {
-            (lifetime_sup.span, suggestion_param_name.clone())
-        } else {
-            (lifetime_sup.span.shrink_to_hi(), suggestion_param_name.clone() + " ")
-        },
-    ];
+            (span, suggestion_param_name.clone())
+        }
+    };
+    let mut suggestions =
+        vec![make_suggestion(lifetime_sub.span), make_suggestion(lifetime_sup.span)];
 
     if introduce_new {
-        let new_param_suggestion = match &generics.params {
-            [] => (generics.span, format!("<{}>", suggestion_param_name)),
-            [first, ..] => (first.span.shrink_to_lo(), format!("{}, ", suggestion_param_name)),
-        };
+        let new_param_suggestion =
+            if let Some(first) = generics.params.iter().find(|p| !p.name.ident().span.is_empty()) {
+                (first.span.shrink_to_lo(), format!("{}, ", suggestion_param_name))
+            } else {
+                (generics.span, format!("<{}>", suggestion_param_name))
+            };
 
         suggestions.push(new_param_suggestion);
     }
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs
index 80500f3..43d5c9f 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs
@@ -85,7 +85,7 @@
                     err.span_suggestion_verbose(
                         span.shrink_to_hi(),
                         "consider relaxing the implicit `'static` requirement",
-                        " + '_".to_string(),
+                        " + '_",
                         Applicability::MaybeIncorrect,
                     );
                 }
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs
index 9948d15..53d9acf 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs
@@ -16,7 +16,7 @@
 
 pub use different_lifetimes::suggest_adding_lifetime_params;
 pub use find_anon_type::find_anon_type;
-pub use static_impl_trait::suggest_new_region_bound;
+pub use static_impl_trait::{suggest_new_region_bound, HirTraitObjectVisitor, TraitObjectVisitor};
 pub use util::find_param_with_region;
 
 impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs
index 3de5273..76cb76d 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs
@@ -4,6 +4,7 @@
 use crate::infer::error_reporting::nice_region_error::NiceRegionError;
 use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed};
 use rustc_middle::ty;
+use rustc_span::symbol::kw;
 
 impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
     /// When given a `ConcreteFailure` for a function with parameters containing a named region and
@@ -67,7 +68,7 @@
         let is_impl_item = region_info.is_impl_item;
 
         match br {
-            ty::BrAnon(_) => {}
+            ty::BrNamed(_, kw::UnderscoreLifetime) | ty::BrAnon(_) => {}
             _ => {
                 /* not an anonymous region */
                 debug!("try_report_named_anon_conflict: not an anonymous region");
@@ -106,7 +107,7 @@
         diag.span_suggestion(
             new_ty_span,
             &format!("add explicit lifetime `{}` to {}", named, span_label_var),
-            new_ty.to_string(),
+            new_ty,
             Applicability::Unspecified,
         );
 
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
index a4c46d5..6935ce9 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
@@ -10,7 +10,7 @@
 use rustc_hir::intravisit::{walk_ty, Visitor};
 use rustc_hir::{self as hir, GenericBound, Item, ItemKind, Lifetime, LifetimeName, Node, TyKind};
 use rustc_middle::ty::{
-    self, AssocItemContainer, StaticLifetimeVisitor, Ty, TyCtxt, TypeFoldable, TypeVisitor,
+    self, AssocItemContainer, StaticLifetimeVisitor, Ty, TyCtxt, TypeSuperFoldable, TypeVisitor,
 };
 use rustc_span::symbol::Ident;
 use rustc_span::Span;
@@ -328,7 +328,7 @@
                         err.span_suggestion_verbose(
                             span,
                             &format!("{} `impl Trait`'s {}", consider, explicit_static),
-                            lifetime_name.clone(),
+                            &lifetime_name,
                             Applicability::MaybeIncorrect,
                         );
                     }
@@ -363,7 +363,7 @@
                             captures = captures,
                             explicit = explicit,
                         ),
-                        plus_lt.clone(),
+                        &plus_lt,
                         Applicability::MaybeIncorrect,
                     );
                 }
@@ -378,7 +378,7 @@
                             captures = captures,
                             explicit = explicit,
                         ),
-                        plus_lt.clone(),
+                        &plus_lt,
                         Applicability::MaybeIncorrect,
                     );
                 }
@@ -391,7 +391,7 @@
                         err.span_suggestion_verbose(
                             lt.span,
                             &format!("{} trait object's {}", consider, explicit_static),
-                            lifetime_name.clone(),
+                            &lifetime_name,
                             Applicability::MaybeIncorrect,
                         );
                     }
@@ -535,7 +535,7 @@
                 err.span_suggestion_verbose(
                     span.shrink_to_hi(),
                     "consider relaxing the implicit `'static` requirement",
-                    " + '_".to_string(),
+                    " + '_",
                     Applicability::MaybeIncorrect,
                 );
                 suggested = true;
@@ -546,7 +546,7 @@
 }
 
 /// Collect all the trait objects in a type that could have received an implicit `'static` lifetime.
-pub(super) struct TraitObjectVisitor(pub(super) FxHashSet<DefId>);
+pub struct TraitObjectVisitor(pub FxHashSet<DefId>);
 
 impl<'tcx> TypeVisitor<'tcx> for TraitObjectVisitor {
     fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
@@ -563,7 +563,7 @@
 }
 
 /// Collect all `hir::Ty<'_>` `Span`s for trait objects with an implicit lifetime.
-pub(super) struct HirTraitObjectVisitor<'a>(pub(super) &'a mut Vec<Span>, pub(super) DefId);
+pub struct HirTraitObjectVisitor<'a>(pub &'a mut Vec<Span>, pub DefId);
 
 impl<'a, 'tcx> Visitor<'tcx> for HirTraitObjectVisitor<'a> {
     fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx>) {
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs
index 1788eb8..17d4bb1 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs
@@ -11,7 +11,7 @@
 use rustc_hir::intravisit::Visitor;
 use rustc_middle::hir::nested_filter;
 use rustc_middle::ty::print::RegionHighlightMode;
-use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeVisitor};
+use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperFoldable, TypeVisitor};
 use rustc_span::{Span, Symbol};
 
 use std::ops::ControlFlow;
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs
index da03d94..b9596cd 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs
@@ -34,6 +34,7 @@
 // i32, which is the type of y but with the anonymous region replaced
 // with 'a, the corresponding bound region and is_first which is true if
 // the hir::Param is the first parameter in the function declaration.
+#[instrument(skip(tcx), level = "debug")]
 pub fn find_param_with_region<'tcx>(
     tcx: TyCtxt<'tcx>,
     anon_region: Region<'tcx>,
@@ -51,9 +52,19 @@
     let hir_id = hir.local_def_id_to_hir_id(id.as_local()?);
     let body_id = hir.maybe_body_owned_by(hir_id)?;
     let body = hir.body(body_id);
+
+    // Don't perform this on closures
+    match hir.get(hir_id) {
+        hir::Node::Expr(&hir::Expr { kind: hir::ExprKind::Closure { .. }, .. }) => {
+            return None;
+        }
+        _ => {}
+    }
+
     let owner_id = hir.body_owner(body_id);
     let fn_decl = hir.fn_decl_by_hir_id(owner_id).unwrap();
     let poly_fn_sig = tcx.fn_sig(id);
+
     let fn_sig = tcx.liberate_late_bound_regions(id, poly_fn_sig);
     body.params
         .iter()
@@ -98,7 +109,7 @@
         &self,
         anon_region: Region<'tcx>,
         replace_region: Region<'tcx>,
-    ) -> Option<AnonymousParamInfo<'_>> {
+    ) -> Option<AnonymousParamInfo<'tcx>> {
         find_param_with_region(self.tcx(), anon_region, replace_region)
     }
 
diff --git a/compiler/rustc_infer/src/infer/error_reporting/note.rs b/compiler/rustc_infer/src/infer/error_reporting/note.rs
index cbdcf01..67bbace 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/note.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/note.rs
@@ -367,17 +367,12 @@
                     .collect();
 
                 if !clauses.is_empty() {
-                    let where_clause_span = self
-                        .tcx
-                        .hir()
-                        .get_generics(impl_item_def_id)
-                        .unwrap()
-                        .where_clause_span
-                        .shrink_to_hi();
+                    let generics = self.tcx.hir().get_generics(impl_item_def_id).unwrap();
+                    let where_clause_span = generics.tail_span_for_predicate_suggestion();
 
                     let suggestion = format!(
                         "{} {}",
-                        if !impl_predicates.is_empty() { "," } else { " where" },
+                        generics.add_where_or_trailing_comma(),
                         clauses.join(", "),
                     );
                     err.span_suggestion(
diff --git a/compiler/rustc_infer/src/infer/freshen.rs b/compiler/rustc_infer/src/infer/freshen.rs
index 0a11a81..024f740 100644
--- a/compiler/rustc_infer/src/infer/freshen.rs
+++ b/compiler/rustc_infer/src/infer/freshen.rs
@@ -34,7 +34,7 @@
 use rustc_data_structures::fx::FxHashMap;
 use rustc_middle::infer::unify_key::ToType;
 use rustc_middle::ty::fold::TypeFolder;
-use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable};
+use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable};
 use std::collections::hash_map::Entry;
 
 pub struct TypeFreshener<'a, 'tcx> {
@@ -218,7 +218,7 @@
     }
 
     fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
-        match ct.val() {
+        match ct.kind() {
             ty::ConstKind::Infer(ty::InferConst::Var(v)) => {
                 let opt_ct = self
                     .infcx
@@ -228,12 +228,7 @@
                     .probe_value(v)
                     .val
                     .known();
-                return self.freshen_const(
-                    opt_ct,
-                    ty::InferConst::Var(v),
-                    ty::InferConst::Fresh,
-                    ct.ty(),
-                );
+                self.freshen_const(opt_ct, ty::InferConst::Var(v), ty::InferConst::Fresh, ct.ty())
             }
             ty::ConstKind::Infer(ty::InferConst::Fresh(i)) => {
                 if i >= self.const_freshen_count {
@@ -244,7 +239,7 @@
                         self.const_freshen_count,
                     );
                 }
-                return ct;
+                ct
             }
 
             ty::ConstKind::Bound(..) | ty::ConstKind::Placeholder(_) => {
@@ -254,9 +249,7 @@
             ty::ConstKind::Param(_)
             | ty::ConstKind::Value(_)
             | ty::ConstKind::Unevaluated(..)
-            | ty::ConstKind::Error(_) => {}
+            | ty::ConstKind::Error(_) => ct.super_fold_with(self),
         }
-
-        ct.super_fold_with(self)
     }
 }
diff --git a/compiler/rustc_infer/src/infer/fudge.rs b/compiler/rustc_infer/src/infer/fudge.rs
index c5b90f7..2f0eadc 100644
--- a/compiler/rustc_infer/src/infer/fudge.rs
+++ b/compiler/rustc_infer/src/infer/fudge.rs
@@ -1,4 +1,4 @@
-use rustc_middle::ty::fold::{TypeFoldable, TypeFolder};
+use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
 use rustc_middle::ty::{self, ConstVid, FloatVid, IntVid, RegionVid, Ty, TyCtxt, TyVid};
 
 use super::type_variable::TypeVariableOrigin;
@@ -229,7 +229,7 @@
     }
 
     fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
-        if let ty::ConstKind::Infer(ty::InferConst::Var(vid)) = ct.val() {
+        if let ty::ConstKind::Infer(ty::InferConst::Var(vid)) = ct.kind() {
             if self.const_vars.0.contains(&vid) {
                 // This variable was created during the fudging.
                 // Recreate it with a fresh variable here.
diff --git a/compiler/rustc_infer/src/infer/glb.rs b/compiler/rustc_infer/src/infer/glb.rs
index 0d38b94..1570a08 100644
--- a/compiler/rustc_infer/src/infer/glb.rs
+++ b/compiler/rustc_infer/src/infer/glb.rs
@@ -95,12 +95,20 @@
         T: Relate<'tcx>,
     {
         debug!("binders(a={:?}, b={:?})", a, b);
-
-        // When higher-ranked types are involved, computing the LUB is
-        // very challenging, switch to invariance. This is obviously
-        // overly conservative but works ok in practice.
-        self.relate_with_variance(ty::Variance::Invariant, ty::VarianceDiagInfo::default(), a, b)?;
-        Ok(a)
+        if a.skip_binder().has_escaping_bound_vars() || b.skip_binder().has_escaping_bound_vars() {
+            // When higher-ranked types are involved, computing the GLB is
+            // very challenging, switch to invariance. This is obviously
+            // overly conservative but works ok in practice.
+            self.relate_with_variance(
+                ty::Variance::Invariant,
+                ty::VarianceDiagInfo::default(),
+                a,
+                b,
+            )?;
+            Ok(a)
+        } else {
+            Ok(ty::Binder::dummy(self.relate(a.skip_binder(), b.skip_binder())?))
+        }
     }
 }
 
diff --git a/compiler/rustc_infer/src/infer/higher_ranked/mod.rs b/compiler/rustc_infer/src/infer/higher_ranked/mod.rs
index 73cc411..c82685d 100644
--- a/compiler/rustc_infer/src/infer/higher_ranked/mod.rs
+++ b/compiler/rustc_infer/src/infer/higher_ranked/mod.rs
@@ -3,78 +3,85 @@
 
 use super::combine::CombineFields;
 use super::{HigherRankedType, InferCtxt};
-
 use crate::infer::CombinedSnapshot;
 use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation};
 use rustc_middle::ty::{self, Binder, TypeFoldable};
 
 impl<'a, 'tcx> CombineFields<'a, 'tcx> {
+    /// Checks whether `for<..> sub <: for<..> sup` holds.
+    ///
+    /// For this to hold, **all** instantiations of the super type
+    /// have to be a super type of **at least one** instantiation of
+    /// the subtype.
+    ///
+    /// This is implemented by first entering a new universe.
+    /// We then replace all bound variables in `sup` with placeholders,
+    /// and all bound variables in `sup` with inference vars.
+    /// We can then just relate the two resulting types as normal.
+    ///
+    /// Note: this is a subtle algorithm. For a full explanation, please see
+    /// the [rustc dev guide][rd]
+    ///
+    /// [rd]: https://rustc-dev-guide.rust-lang.org/borrow_check/region_inference/placeholders_and_universes.html
     #[instrument(skip(self), level = "debug")]
     pub fn higher_ranked_sub<T>(
         &mut self,
-        a: Binder<'tcx, T>,
-        b: Binder<'tcx, T>,
-        a_is_expected: bool,
-    ) -> RelateResult<'tcx, Binder<'tcx, T>>
+        sub: Binder<'tcx, T>,
+        sup: Binder<'tcx, T>,
+        sub_is_expected: bool,
+    ) -> RelateResult<'tcx, ()>
     where
         T: Relate<'tcx>,
     {
-        // Rather than checking the subtype relationship between `a` and `b`
-        // as-is, we need to do some extra work here in order to make sure
-        // that function subtyping works correctly with respect to regions
-        //
-        // Note: this is a subtle algorithm.  For a full explanation, please see
-        // the rustc dev guide:
-        // <https://rustc-dev-guide.rust-lang.org/borrow_check/region_inference/placeholders_and_universes.html>
-
         let span = self.trace.cause.span;
 
         self.infcx.commit_if_ok(|_| {
             // First, we instantiate each bound region in the supertype with a
-            // fresh placeholder region.
-            let b_prime = self.infcx.replace_bound_vars_with_placeholders(b);
+            // fresh placeholder region. Note that this automatically creates
+            // a new universe if needed.
+            let sup_prime = self.infcx.replace_bound_vars_with_placeholders(sup);
 
             // Next, we instantiate each bound region in the subtype
             // with a fresh region variable. These region variables --
             // but no other pre-existing region variables -- can name
             // the placeholders.
-            let (a_prime, _) =
-                self.infcx.replace_bound_vars_with_fresh_vars(span, HigherRankedType, a);
+            let sub_prime =
+                self.infcx.replace_bound_vars_with_fresh_vars(span, HigherRankedType, sub);
 
-            debug!("a_prime={:?}", a_prime);
-            debug!("b_prime={:?}", b_prime);
+            debug!("a_prime={:?}", sub_prime);
+            debug!("b_prime={:?}", sup_prime);
 
             // Compare types now that bound regions have been replaced.
-            let result = self.sub(a_is_expected).relate(a_prime, b_prime)?;
+            let result = self.sub(sub_is_expected).relate(sub_prime, sup_prime)?;
 
-            debug!("higher_ranked_sub: OK result={:?}", result);
-
-            // We related `a_prime` and `b_prime`, which just had any bound vars
-            // replaced with placeholders or infer vars, respectively. Relating
-            // them should not introduce new bound vars.
-            Ok(ty::Binder::dummy(result))
+            debug!("higher_ranked_sub: OK result={result:?}");
+            // NOTE: returning the result here would be dangerous as it contains
+            // placeholders which **must not** be named afterwards.
+            Ok(())
         })
     }
 }
 
 impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
     /// Replaces all bound variables (lifetimes, types, and constants) bound by
-    /// `binder` with placeholder variables.
+    /// `binder` with placeholder variables in a new universe. This means that the
+    /// new placeholders can only be named by inference variables created after
+    /// this method has been called.
     ///
     /// This is the first step of checking subtyping when higher-ranked things are involved.
     /// For more details visit the relevant sections of the [rustc dev guide].
     ///
     /// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/hrtb.html
+    #[instrument(level = "debug", skip(self))]
     pub fn replace_bound_vars_with_placeholders<T>(&self, binder: ty::Binder<'tcx, T>) -> T
     where
-        T: TypeFoldable<'tcx>,
+        T: TypeFoldable<'tcx> + Copy,
     {
-        // Figure out what the next universe will be, but don't actually create
-        // it until after we've done the substitution (in particular there may
-        // be no bound variables). This is a performance optimization, since the
-        // leak check for example can be skipped if no new universes are created
-        // (i.e., if there are no placeholders).
-        let next_universe = self.universe().next_universe();
+        if let Some(inner) = binder.no_bound_vars() {
+            return inner;
+        }
+
+        let next_universe = self.create_next_universe();
 
         let fld_r = |br: ty::BoundRegion| {
             self.tcx.mk_region(ty::RePlaceholder(ty::PlaceholderRegion {
@@ -92,7 +99,7 @@
 
         let fld_c = |bound_var: ty::BoundVar, ty| {
             self.tcx.mk_const(ty::ConstS {
-                val: ty::ConstKind::Placeholder(ty::PlaceholderConst {
+                kind: ty::ConstKind::Placeholder(ty::PlaceholderConst {
                     universe: next_universe,
                     name: ty::BoundConst { var: bound_var, ty },
                 }),
@@ -100,23 +107,8 @@
             })
         };
 
-        let (result, map) = self.tcx.replace_bound_vars(binder, fld_r, fld_t, fld_c);
-
-        // If there were higher-ranked regions to replace, then actually create
-        // the next universe (this avoids needlessly creating universes).
-        if !map.is_empty() {
-            let n_u = self.create_next_universe();
-            assert_eq!(n_u, next_universe);
-        }
-
-        debug!(
-            "replace_bound_vars_with_placeholders(\
-             next_universe={:?}, \
-             result={:?}, \
-             map={:?})",
-            next_universe, result, map,
-        );
-
+        let result = self.tcx.replace_bound_vars_uncached(binder, fld_r, fld_t, fld_c);
+        debug!(?next_universe, ?result);
         result
     }
 
diff --git a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
index 0f341a9..455de47 100644
--- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
+++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
@@ -7,7 +7,6 @@
 use crate::infer::region_constraints::VerifyBound;
 use crate::infer::RegionRelations;
 use crate::infer::RegionVariableOrigin;
-use crate::infer::RegionckMode;
 use crate::infer::SubregionOrigin;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::graph::implementation::{
@@ -23,6 +22,8 @@
 use rustc_span::Span;
 use std::fmt;
 
+use super::outlives::test_type_match;
+
 /// 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,
@@ -30,46 +31,27 @@
 /// all the variables as well as a set of errors that must be reported.
 #[instrument(level = "debug", skip(region_rels, var_infos, data))]
 pub(crate) fn resolve<'tcx>(
+    param_env: ty::ParamEnv<'tcx>,
     region_rels: &RegionRelations<'_, 'tcx>,
     var_infos: VarInfos,
     data: RegionConstraintData<'tcx>,
-    mode: RegionckMode,
 ) -> (LexicalRegionResolutions<'tcx>, Vec<RegionResolutionError<'tcx>>) {
     let mut errors = vec![];
-    let mut resolver = LexicalResolver { region_rels, var_infos, data };
-    match mode {
-        RegionckMode::Solve => {
-            let values = resolver.infer_variable_values(&mut errors);
-            (values, errors)
-        }
-        RegionckMode::Erase { suppress_errors: false } => {
-            // Do real inference to get errors, then erase the results.
-            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| match *v {
-                VarValue::Value(ref mut r) => *r = re_erased,
-                VarValue::ErrorValue => {}
-            });
-            (values, errors)
-        }
-        RegionckMode::Erase { suppress_errors: true } => {
-            // Skip region inference entirely.
-            (resolver.erased_data(region_rels.tcx), Vec::new())
-        }
-    }
+    let mut resolver = LexicalResolver { param_env, region_rels, var_infos, data };
+    let values = resolver.infer_variable_values(&mut errors);
+    (values, errors)
 }
 
 /// Contains the result of lexical region resolution. Offers methods
 /// to lookup up the final value of a region variable.
 #[derive(Clone)]
 pub struct LexicalRegionResolutions<'tcx> {
-    values: IndexVec<RegionVid, VarValue<'tcx>>,
-    error_region: ty::Region<'tcx>,
+    pub(crate) values: IndexVec<RegionVid, VarValue<'tcx>>,
+    pub(crate) error_region: ty::Region<'tcx>,
 }
 
 #[derive(Copy, Clone, Debug)]
-enum VarValue<'tcx> {
+pub(crate) enum VarValue<'tcx> {
     Value(Region<'tcx>),
     ErrorValue,
 }
@@ -121,6 +103,7 @@
 type RegionGraph<'tcx> = Graph<(), Constraint<'tcx>>;
 
 struct LexicalResolver<'cx, 'tcx> {
+    param_env: ty::ParamEnv<'tcx>,
     region_rels: &'cx RegionRelations<'cx, 'tcx>,
     var_infos: VarInfos,
     data: RegionConstraintData<'tcx>,
@@ -173,19 +156,6 @@
         }
     }
 
-    /// An erased version of the lexical region resolutions. Used when we're
-    /// erasing regions and suppressing errors: in item bodies with
-    /// `-Zborrowck=mir`.
-    fn erased_data(&self, tcx: TyCtxt<'tcx>) -> LexicalRegionResolutions<'tcx> {
-        LexicalRegionResolutions {
-            error_region: tcx.lifetimes.re_static,
-            values: IndexVec::from_elem_n(
-                VarValue::Value(tcx.lifetimes.re_erased),
-                self.num_vars(),
-            ),
-        }
-    }
-
     fn dump_constraints(&self, free_regions: &RegionRelations<'_, 'tcx>) {
         debug!("----() Start constraint listing (context={:?}) ()----", free_regions.context);
         for (idx, (constraint, _)) in self.data.constraints.iter().enumerate() {
@@ -852,9 +822,20 @@
         min: ty::Region<'tcx>,
     ) -> bool {
         match bound {
-            VerifyBound::IfEq(k, b) => {
-                (var_values.normalize(self.region_rels.tcx, *k) == generic_ty)
-                    && self.bound_is_met(b, var_values, generic_ty, min)
+            VerifyBound::IfEq(verify_if_eq_b) => {
+                let verify_if_eq_b = var_values.normalize(self.region_rels.tcx, *verify_if_eq_b);
+                match test_type_match::extract_verify_if_eq(
+                    self.tcx(),
+                    self.param_env,
+                    &verify_if_eq_b,
+                    generic_ty,
+                ) {
+                    Some(r) => {
+                        self.bound_is_met(&VerifyBound::OutlivedBy(r), var_values, generic_ty, min)
+                    }
+
+                    None => false,
+                }
             }
 
             VerifyBound::OutlivedBy(r) => {
diff --git a/compiler/rustc_infer/src/infer/lub.rs b/compiler/rustc_infer/src/infer/lub.rs
index 498c1e9..9f96d52 100644
--- a/compiler/rustc_infer/src/infer/lub.rs
+++ b/compiler/rustc_infer/src/infer/lub.rs
@@ -95,12 +95,20 @@
         T: Relate<'tcx>,
     {
         debug!("binders(a={:?}, b={:?})", a, b);
-
-        // When higher-ranked types are involved, computing the LUB is
-        // very challenging, switch to invariance. This is obviously
-        // overly conservative but works ok in practice.
-        self.relate_with_variance(ty::Variance::Invariant, ty::VarianceDiagInfo::default(), a, b)?;
-        Ok(a)
+        if a.skip_binder().has_escaping_bound_vars() || b.skip_binder().has_escaping_bound_vars() {
+            // When higher-ranked types are involved, computing the LUB is
+            // very challenging, switch to invariance. This is obviously
+            // overly conservative but works ok in practice.
+            self.relate_with_variance(
+                ty::Variance::Invariant,
+                ty::VarianceDiagInfo::default(),
+                a,
+                b,
+            )?;
+            Ok(a)
+        } else {
+            Ok(ty::Binder::dummy(self.relate(a.skip_binder(), b.skip_binder())?))
+        }
     }
 }
 
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index c9121f7..3ff14a1 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -20,21 +20,19 @@
 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::mir::interpret::{ErrorHandled, EvalToConstValueResult};
+use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult};
 use rustc_middle::traits::select;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
-use rustc_middle::ty::fold::{TypeFoldable, TypeFolder};
+use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
 use rustc_middle::ty::relate::RelateResult;
 use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, SubstsRef};
 pub use rustc_middle::ty::IntVarValue;
 use rustc_middle::ty::{self, GenericParamDefKind, InferConst, Ty, TyCtxt};
 use rustc_middle::ty::{ConstVid, FloatVid, IntVid, TyVid};
-use rustc_session::config::BorrowckMode;
 use rustc_span::symbol::Symbol;
 use rustc_span::Span;
 
 use std::cell::{Cell, Ref, RefCell};
-use std::collections::BTreeMap;
 use std::fmt;
 
 use self::combine::CombineFields;
@@ -86,42 +84,6 @@
     ut::InPlace<T, &'a mut ut::UnificationStorage<T>, &'a mut InferCtxtUndoLogs<'tcx>>,
 >;
 
-/// How we should handle region solving.
-///
-/// This is used so that the region values inferred by HIR region solving are
-/// not exposed, and so that we can avoid doing work in HIR typeck that MIR
-/// typeck will also do.
-#[derive(Copy, Clone, Debug, Default)]
-pub enum RegionckMode {
-    /// The default mode: report region errors, don't erase regions.
-    #[default]
-    Solve,
-    /// Erase the results of region after solving.
-    Erase {
-        /// A flag that is used to suppress region errors, when we are doing
-        /// region checks that the NLL borrow checker will also do -- it might
-        /// be set to true.
-        suppress_errors: bool,
-    },
-}
-
-impl RegionckMode {
-    /// Indicates that the MIR borrowck will repeat these region
-    /// checks, so we should ignore errors if NLL is (unconditionally)
-    /// enabled.
-    pub fn for_item_body(tcx: TyCtxt<'_>) -> Self {
-        // FIXME(Centril): Once we actually remove `::Migrate` also make
-        // this always `true` and then proceed to eliminate the dead code.
-        match tcx.borrowck_mode() {
-            // If we're on Migrate mode, report AST region errors
-            BorrowckMode::Migrate => RegionckMode::Erase { suppress_errors: false },
-
-            // If we're on MIR, don't report AST region errors as they should be reported by NLL
-            BorrowckMode::Mir => RegionckMode::Erase { suppress_errors: true },
-        }
-    }
-}
-
 /// This type contains all the things within `InferCtxt` that sit within a
 /// `RefCell` and are involved with taking/rolling back snapshots. Snapshot
 /// operations are hot enough that we want only one call to `borrow_mut` per
@@ -181,7 +143,7 @@
     ///
     /// Before running `resolve_regions_and_report_errors`, the creator
     /// of the inference context is expected to invoke
-    /// `process_region_obligations` (defined in `self::region_obligations`)
+    /// [`InferCtxt::process_registered_region_obligations`]
     /// for each body-id in this map, which will process the
     /// obligations within. This is expected to be done 'late enough'
     /// that all type inference variables have been bound and so forth.
@@ -929,6 +891,10 @@
             .region_constraints_added_in_snapshot(&snapshot.undo_snapshot)
     }
 
+    pub fn opaque_types_added_in_snapshot(&self, snapshot: &CombinedSnapshot<'a, 'tcx>) -> bool {
+        self.inner.borrow().undo_log.opaque_types_in_snapshot(&snapshot.undo_snapshot)
+    }
+
     pub fn add_given(&self, sub: ty::Region<'tcx>, sup: ty::RegionVid) {
         self.inner.borrow_mut().unwrap_region_constraints().add_given(sub, sup);
     }
@@ -1272,6 +1238,33 @@
         self.tainted_by_errors_flag.set(true)
     }
 
+    pub fn skip_region_resolution(&self) {
+        let (var_infos, _) = {
+            let mut inner = self.inner.borrow_mut();
+            let inner = &mut *inner;
+            // Note: `inner.region_obligations` may not be empty, because we
+            // didn't necessarily call `process_registered_region_obligations`.
+            // This is okay, because that doesn't introduce new vars.
+            inner
+                .region_constraint_storage
+                .take()
+                .expect("regions already resolved")
+                .with_log(&mut inner.undo_log)
+                .into_infos_and_data()
+        };
+
+        let lexical_region_resolutions = LexicalRegionResolutions {
+            error_region: self.tcx.lifetimes.re_static,
+            values: rustc_index::vec::IndexVec::from_elem_n(
+                crate::infer::lexical_region_resolve::VarValue::Value(self.tcx.lifetimes.re_erased),
+                var_infos.len(),
+            ),
+        };
+
+        let old_value = self.lexical_region_resolutions.replace(Some(lexical_region_resolutions));
+        assert!(old_value.is_none());
+    }
+
     /// Process the region constraints and return any any errors that
     /// result. After this, no more unification operations should be
     /// done -- or the compiler will panic -- but it is legal to use
@@ -1280,7 +1273,6 @@
         &self,
         region_context: DefId,
         outlives_env: &OutlivesEnvironment<'tcx>,
-        mode: RegionckMode,
     ) -> Vec<RegionResolutionError<'tcx>> {
         let (var_infos, data) = {
             let mut inner = self.inner.borrow_mut();
@@ -1302,7 +1294,7 @@
             &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);
+            lexical_region_resolve::resolve(outlives_env.param_env, region_rels, var_infos, data);
 
         let old_value = self.lexical_region_resolutions.replace(Some(lexical_region_resolutions));
         assert!(old_value.is_none());
@@ -1318,9 +1310,8 @@
         &self,
         region_context: DefId,
         outlives_env: &OutlivesEnvironment<'tcx>,
-        mode: RegionckMode,
     ) {
-        let errors = self.resolve_regions(region_context, outlives_env, mode);
+        let errors = self.resolve_regions(region_context, outlives_env);
 
         if !self.is_tainted_by_errors() {
             // As a heuristic, just skip reporting region errors
@@ -1547,25 +1538,40 @@
         span: Span,
         lbrct: LateBoundRegionConversionTime,
         value: ty::Binder<'tcx, T>,
-    ) -> (T, BTreeMap<ty::BoundRegion, ty::Region<'tcx>>)
+    ) -> T
     where
-        T: TypeFoldable<'tcx>,
+        T: TypeFoldable<'tcx> + Copy,
     {
-        let fld_r =
-            |br: ty::BoundRegion| self.next_region_var(LateBoundRegion(span, br.kind, lbrct));
-        let fld_t = |_| {
-            self.next_ty_var(TypeVariableOrigin {
-                kind: TypeVariableOriginKind::MiscVariable,
-                span,
+        if let Some(inner) = value.no_bound_vars() {
+            return inner;
+        }
+
+        let mut region_map = FxHashMap::default();
+        let fld_r = |br: ty::BoundRegion| {
+            *region_map
+                .entry(br)
+                .or_insert_with(|| self.next_region_var(LateBoundRegion(span, br.kind, lbrct)))
+        };
+
+        let mut ty_map = FxHashMap::default();
+        let fld_t = |bt: ty::BoundTy| {
+            *ty_map.entry(bt).or_insert_with(|| {
+                self.next_ty_var(TypeVariableOrigin {
+                    kind: TypeVariableOriginKind::MiscVariable,
+                    span,
+                })
             })
         };
-        let fld_c = |_, ty| {
-            self.next_const_var(
-                ty,
-                ConstVariableOrigin { kind: ConstVariableOriginKind::MiscVariable, span },
-            )
+        let mut ct_map = FxHashMap::default();
+        let fld_c = |bc: ty::BoundVar, ty| {
+            *ct_map.entry(bc).or_insert_with(|| {
+                self.next_const_var(
+                    ty,
+                    ConstVariableOrigin { kind: ConstVariableOriginKind::MiscVariable, span },
+                )
+            })
         };
-        self.tcx.replace_bound_vars(value, fld_r, fld_t, fld_c)
+        self.tcx.replace_bound_vars_uncached(value, fld_r, fld_t, fld_c)
     }
 
     /// See the [`region_constraints::RegionConstraintCollector::verify_generic_bound`] method.
@@ -1614,6 +1620,28 @@
         u
     }
 
+    pub fn try_const_eval_resolve(
+        &self,
+        param_env: ty::ParamEnv<'tcx>,
+        unevaluated: ty::Unevaluated<'tcx>,
+        ty: Ty<'tcx>,
+        span: Option<Span>,
+    ) -> Result<ty::Const<'tcx>, ErrorHandled> {
+        match self.const_eval_resolve(param_env, unevaluated, span) {
+            Ok(Some(val)) => Ok(ty::Const::from_value(self.tcx, val, ty)),
+            Ok(None) => {
+                let tcx = self.tcx;
+                let def_id = unevaluated.def.did;
+                span_bug!(
+                    tcx.def_span(def_id),
+                    "unable to construct a constant value for the unevaluated constant {:?}",
+                    unevaluated
+                );
+            }
+            Err(err) => Err(err),
+        }
+    }
+
     /// Resolves and evaluates a constant.
     ///
     /// The constant can be located on a trait like `<A as B>::C`, in which case the given
@@ -1632,7 +1660,7 @@
         param_env: ty::ParamEnv<'tcx>,
         unevaluated: ty::Unevaluated<'tcx>,
         span: Option<Span>,
-    ) -> EvalToConstValueResult<'tcx> {
+    ) -> EvalToValTreeResult<'tcx> {
         let substs = self.resolve_vars_if_possible(unevaluated.substs);
         debug!(?substs);
 
@@ -1656,7 +1684,7 @@
 
         // The return value is the evaluated value which doesn't contain any reference to inference
         // variables, thus we don't need to substitute back the original values.
-        self.tcx.const_eval_resolve(param_env_erased, unevaluated, span)
+        self.tcx.const_eval_resolve_for_typeck(param_env_erased, unevaluated, span)
     }
 
     /// `ty_or_const_infer_var_changed` is equivalent to one of these two:
@@ -1752,7 +1780,7 @@
     /// Tries to extract an inference variable from a constant, returns `None`
     /// for constants other than `ty::ConstKind::Infer(_)` (or `InferConst::Fresh`).
     pub fn maybe_from_const(ct: ty::Const<'tcx>) -> Option<Self> {
-        match ct.val() {
+        match ct.kind() {
             ty::ConstKind::Infer(InferConst::Var(v)) => Some(TyOrConstInferVar::Const(v)),
             _ => None,
         }
@@ -1831,7 +1859,7 @@
     }
 
     fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
-        if let ty::ConstKind::Infer(InferConst::Var(vid)) = ct.val() {
+        if let ty::ConstKind::Infer(InferConst::Var(vid)) = ct.kind() {
             self.infcx
                 .inner
                 .borrow_mut()
diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs
index 94a795f..846e7f7 100644
--- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs
+++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs
@@ -27,7 +27,7 @@
 use crate::infer::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_middle::ty::error::TypeError;
-use rustc_middle::ty::fold::{TypeFoldable, TypeVisitor};
+use rustc_middle::ty::fold::{TypeFoldable, TypeSuperFoldable, TypeVisitor};
 use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation};
 use rustc_middle::ty::{self, InferConst, Ty, TyCtxt};
 use rustc_span::Span;
@@ -659,10 +659,14 @@
             b = self.infcx.shallow_resolve(b);
         }
 
-        match b.val() {
+        match b.kind() {
             ty::ConstKind::Infer(InferConst::Var(_)) if D::forbid_inference_vars() => {
                 // Forbid inference variables in the RHS.
-                bug!("unexpected inference var {:?}", b)
+                self.infcx.tcx.sess.delay_span_bug(
+                    self.delegate.span(),
+                    format!("unexpected inference var {:?}", b,),
+                );
+                Ok(a)
             }
             // FIXME(invariance): see the related FIXME above.
             _ => self.infcx.super_combine_consts(self, a, b),
@@ -859,7 +863,7 @@
 
     delegate: &'me mut D,
 
-    /// After we generalize this type, we are going to relative it to
+    /// After we generalize this type, we are going to relate it to
     /// some other type. What will be the variance at this point?
     ambient_variance: ty::Variance,
 
@@ -1034,7 +1038,7 @@
         a: ty::Const<'tcx>,
         _: ty::Const<'tcx>,
     ) -> RelateResult<'tcx, ty::Const<'tcx>> {
-        match a.val() {
+        match a.kind() {
             ty::ConstKind::Infer(InferConst::Var(_)) if D::forbid_inference_vars() => {
                 bug!("unexpected inference variable encountered in NLL generalization: {:?}", a);
             }
diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs
index 92c0ed8..41a5370 100644
--- a/compiler/rustc_infer/src/infer/opaque_types.rs
+++ b/compiler/rustc_infer/src/infer/opaque_types.rs
@@ -5,11 +5,11 @@
 use rustc_data_structures::sync::Lrc;
 use rustc_data_structures::vec_map::VecMap;
 use rustc_hir as hir;
-use rustc_middle::traits::ObligationCause;
+use rustc_middle::traits::{ObligationCause, ObligationCauseCode};
 use rustc_middle::ty::fold::BottomUpFolder;
 use rustc_middle::ty::subst::{GenericArgKind, Subst};
 use rustc_middle::ty::{
-    self, OpaqueHiddenType, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable, TypeVisitor,
+    self, OpaqueHiddenType, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable, TypeVisitor,
 };
 use rustc_span::Span;
 
@@ -46,6 +46,7 @@
         value: T,
         body_id: HirId,
         span: Span,
+        code: ObligationCauseCode<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
     ) -> InferOk<'tcx, T> {
         if !value.has_opaque_types() {
@@ -68,10 +69,13 @@
                     ) =>
                 {
                     let span = if span.is_dummy() { self.tcx.def_span(def_id) } else { span };
-                    let cause = ObligationCause::misc(span, body_id);
+                    let cause = ObligationCause::new(span, body_id, code.clone());
+                    // FIXME(compiler-errors): We probably should add a new TypeVariableOriginKind
+                    // for opaque types, and then use that kind to fix the spans for type errors
+                    // that we see later on.
                     let ty_var = self.next_ty_var(TypeVariableOrigin {
                         kind: TypeVariableOriginKind::TypeInference,
-                        span: cause.span,
+                        span,
                     });
                     obligations.extend(
                         self.handle_opaque_type(ty, ty_var, true, &cause, param_env)
@@ -99,7 +103,7 @@
         }
         let (a, b) = if a_is_expected { (a, b) } else { (b, a) };
         let process = |a: Ty<'tcx>, b: Ty<'tcx>| match *a.kind() {
-            ty::Opaque(def_id, substs) => {
+            ty::Opaque(def_id, substs) if def_id.is_local() => {
                 let origin = if self.defining_use_anchor.is_some() {
                     // Check that this is `impl Trait` type is
                     // declared by `parent_def_id` -- i.e., one whose
@@ -470,7 +474,7 @@
         &mut self,
         t: &ty::Binder<'tcx, T>,
     ) -> ControlFlow<Self::BreakTy> {
-        t.as_ref().skip_binder().visit_with(self);
+        t.super_visit_with(self);
         ControlFlow::CONTINUE
     }
 
diff --git a/compiler/rustc_infer/src/infer/outlives/mod.rs b/compiler/rustc_infer/src/infer/outlives/mod.rs
index 03d6c45..2a08528 100644
--- a/compiler/rustc_infer/src/infer/outlives/mod.rs
+++ b/compiler/rustc_infer/src/infer/outlives/mod.rs
@@ -3,15 +3,16 @@
 pub mod components;
 pub mod env;
 pub mod obligations;
+pub mod test_type_match;
 pub mod verify;
 
 use rustc_middle::traits::query::OutlivesBound;
 use rustc_middle::ty;
 
+#[instrument(level = "debug", skip(param_env))]
 pub fn explicit_outlives_bounds<'tcx>(
     param_env: ty::ParamEnv<'tcx>,
 ) -> impl Iterator<Item = OutlivesBound<'tcx>> + 'tcx {
-    debug!("explicit_outlives_bounds()");
     param_env
         .caller_bounds()
         .into_iter()
diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs
index 19d03ff..a268493 100644
--- a/compiler/rustc_infer/src/infer/outlives/obligations.rs
+++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs
@@ -136,7 +136,7 @@
     ///
     /// # Parameters
     ///
-    /// - `region_bound_pairs`: the set of region bounds implied by
+    /// - `region_bound_pairs_map`: the set of region bounds implied by
     ///   the parameters and where-clauses. In particular, each pair
     ///   `('a, K)` in this list tells us that the bounds in scope
     ///   indicate that `K: 'a`, where `K` is either a generic
@@ -147,12 +147,6 @@
     /// - `param_env` is the parameter environment for the enclosing function.
     /// - `body_id` is the body-id whose region obligations are being
     ///   processed.
-    ///
-    /// # Returns
-    ///
-    /// This function may have to perform normalizations, and hence it
-    /// returns an `InferOk` with subobligations that must be
-    /// processed.
     #[instrument(level = "debug", skip(self, region_bound_pairs_map))]
     pub fn process_registered_region_obligations(
         &self,
@@ -324,17 +318,13 @@
         self.delegate.push_verify(origin, generic, region, verify_bound);
     }
 
+    #[tracing::instrument(level = "debug", skip(self))]
     fn projection_must_outlive(
         &mut self,
         origin: infer::SubregionOrigin<'tcx>,
         region: ty::Region<'tcx>,
         projection_ty: ty::ProjectionTy<'tcx>,
     ) {
-        debug!(
-            "projection_must_outlive(region={:?}, projection_ty={:?}, origin={:?})",
-            region, projection_ty, origin
-        );
-
         // This case is thorny for inference. The fundamental problem is
         // that there are many cases where we have choice, and inference
         // doesn't like choice (the current region inference in
@@ -369,13 +359,21 @@
         // #55756) in cases where you have e.g., `<T as Foo<'a>>::Item:
         // 'a` in the environment but `trait Foo<'b> { type Item: 'b
         // }` in the trait definition.
-        approx_env_bounds.retain(|bound| match *bound.0.kind() {
-            ty::Projection(projection_ty) => self
-                .verify_bound
-                .projection_declared_bounds_from_trait(projection_ty)
-                .all(|r| r != bound.1),
+        approx_env_bounds.retain(|bound_outlives| {
+            // OK to skip binder because we only manipulate and compare against other
+            // values from the same binder. e.g. if we have (e.g.) `for<'a> <T as Trait<'a>>::Item: 'a`
+            // in `bound`, the `'a` will be a `^1` (bound, debruijn index == innermost) region.
+            // If the declaration is `trait Trait<'b> { type Item: 'b; }`, then `projection_declared_bounds_from_trait`
+            // will be invoked with `['b => ^1]` and so we will get `^1` returned.
+            let bound = bound_outlives.skip_binder();
+            match *bound.0.kind() {
+                ty::Projection(projection_ty) => self
+                    .verify_bound
+                    .projection_declared_bounds_from_trait(projection_ty)
+                    .all(|r| r != bound.1),
 
-            _ => panic!("expected only projection types from env, not {:?}", bound.0),
+                _ => panic!("expected only projection types from env, not {:?}", bound.0),
+            }
         });
 
         // If declared bounds list is empty, the only applicable rule is
@@ -426,8 +424,16 @@
         if !trait_bounds.is_empty()
             && trait_bounds[1..]
                 .iter()
-                .chain(approx_env_bounds.iter().map(|b| &b.1))
-                .all(|b| *b == trait_bounds[0])
+                .map(|r| Some(*r))
+                .chain(
+                    // NB: The environment may contain `for<'a> T: 'a` style bounds.
+                    // In that case, we don't know if they are equal to the trait bound
+                    // or not (since we don't *know* whether the environment bound even applies),
+                    // so just map to `None` here if there are bound vars, ensuring that
+                    // the call to `all` will fail below.
+                    approx_env_bounds.iter().map(|b| b.map_bound(|b| b.1).no_bound_vars()),
+                )
+                .all(|b| b == Some(trait_bounds[0]))
         {
             let unique_bound = trait_bounds[0];
             debug!("projection_must_outlive: unique trait bound = {:?}", unique_bound);
@@ -443,6 +449,7 @@
         // even though a satisfactory solution exists.
         let generic = GenericKind::Projection(projection_ty);
         let verify_bound = self.verify_bound.generic_bound(generic);
+        debug!("projection_must_outlive: pushing {:?}", verify_bound);
         self.delegate.push_verify(origin, generic, region, verify_bound);
     }
 }
diff --git a/compiler/rustc_infer/src/infer/outlives/test_type_match.rs b/compiler/rustc_infer/src/infer/outlives/test_type_match.rs
new file mode 100644
index 0000000..9f71eba
--- /dev/null
+++ b/compiler/rustc_infer/src/infer/outlives/test_type_match.rs
@@ -0,0 +1,207 @@
+use std::collections::hash_map::Entry;
+
+use rustc_data_structures::fx::FxHashMap;
+use rustc_middle::ty::TypeFoldable;
+use rustc_middle::ty::{
+    self,
+    error::TypeError,
+    relate::{self, Relate, RelateResult, TypeRelation},
+    Ty, TyCtxt,
+};
+
+use crate::infer::region_constraints::VerifyIfEq;
+
+/// Given a "verify-if-eq" type test like:
+///
+///     exists<'a...> {
+///         verify_if_eq(some_type, bound_region)
+///     }
+///
+/// and the type `test_ty` that the type test is being tested against,
+/// returns:
+///
+/// * `None` if `some_type` cannot be made equal to `test_ty`,
+///   no matter the values of the variables in `exists`.
+/// * `Some(r)` with a suitable bound (typically the value of `bound_region`, modulo
+///   any bound existential variables, which will be substituted) for the
+///   type under test.
+///
+/// NB: This function uses a simplistic, syntactic version of type equality.
+/// In other words, it may spuriously return `None` even if the type-under-test
+/// is in fact equal to `some_type`. In practice, though, this is used on types
+/// that are either projections like `T::Item` or `T` and it works fine, but it
+/// could have trouble when complex types with higher-ranked binders and the
+/// like are used. This is a particular challenge since this function is invoked
+/// very late in inference and hence cannot make use of the normal inference
+/// machinery.
+#[tracing::instrument(level = "debug", skip(tcx, param_env))]
+pub fn extract_verify_if_eq<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+    verify_if_eq_b: &ty::Binder<'tcx, VerifyIfEq<'tcx>>,
+    test_ty: Ty<'tcx>,
+) -> Option<ty::Region<'tcx>> {
+    assert!(!verify_if_eq_b.has_escaping_bound_vars());
+    let mut m = Match::new(tcx, param_env);
+    let verify_if_eq = verify_if_eq_b.skip_binder();
+    m.relate(verify_if_eq.ty, test_ty).ok()?;
+
+    if let ty::RegionKind::ReLateBound(depth, br) = verify_if_eq.bound.kind() {
+        assert!(depth == ty::INNERMOST);
+        match m.map.get(&br) {
+            Some(&r) => Some(r),
+            None => {
+                // If there is no mapping, then this region is unconstrained.
+                // In that case, we escalate to `'static`.
+                Some(tcx.lifetimes.re_static)
+            }
+        }
+    } else {
+        // The region does not contain any bound variables, so we don't need
+        // to do any substitution.
+        //
+        // Example:
+        //
+        // for<'a> <T as Foo<'a>>::Item: 'b
+        //
+        // In this case, we've now matched and found a value for
+        // `'a`, but it doesn't affect the bound `'b`.
+        Some(verify_if_eq.bound)
+    }
+}
+
+/// True if a (potentially higher-ranked) outlives
+#[tracing::instrument(level = "debug", skip(tcx, param_env))]
+pub(super) fn can_match_erased_ty<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+    outlives_predicate: ty::Binder<'tcx, ty::TypeOutlivesPredicate<'tcx>>,
+    erased_ty: Ty<'tcx>,
+) -> bool {
+    assert!(!outlives_predicate.has_escaping_bound_vars());
+    let erased_outlives_predicate = tcx.erase_regions(outlives_predicate);
+    let outlives_ty = erased_outlives_predicate.skip_binder().0;
+    if outlives_ty == erased_ty {
+        // pointless micro-optimization
+        true
+    } else {
+        Match::new(tcx, param_env).relate(outlives_ty, erased_ty).is_ok()
+    }
+}
+
+struct Match<'tcx> {
+    tcx: TyCtxt<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+    pattern_depth: ty::DebruijnIndex,
+    map: FxHashMap<ty::BoundRegion, ty::Region<'tcx>>,
+}
+
+impl<'tcx> Match<'tcx> {
+    fn new(tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Match<'tcx> {
+        Match { tcx, param_env, pattern_depth: ty::INNERMOST, map: FxHashMap::default() }
+    }
+}
+
+impl<'tcx> Match<'tcx> {
+    /// Creates the "Error" variant that signals "no match".
+    fn no_match<T>(&self) -> RelateResult<'tcx, T> {
+        Err(TypeError::Mismatch)
+    }
+
+    /// Binds the pattern variable `br` to `value`; returns an `Err` if the pattern
+    /// is already bound to a different value.
+    #[tracing::instrument(level = "debug", skip(self))]
+    fn bind(
+        &mut self,
+        br: ty::BoundRegion,
+        value: ty::Region<'tcx>,
+    ) -> RelateResult<'tcx, ty::Region<'tcx>> {
+        match self.map.entry(br) {
+            Entry::Occupied(entry) => {
+                if *entry.get() == value {
+                    Ok(value)
+                } else {
+                    self.no_match()
+                }
+            }
+            Entry::Vacant(entry) => {
+                entry.insert(value);
+                Ok(value)
+            }
+        }
+    }
+}
+
+impl<'tcx> TypeRelation<'tcx> for Match<'tcx> {
+    fn tag(&self) -> &'static str {
+        "Match"
+    }
+    fn tcx(&self) -> TyCtxt<'tcx> {
+        self.tcx
+    }
+    fn param_env(&self) -> ty::ParamEnv<'tcx> {
+        self.param_env
+    }
+    fn a_is_expected(&self) -> bool {
+        true
+    } // irrelevant
+
+    fn relate_with_variance<T: Relate<'tcx>>(
+        &mut self,
+        _: ty::Variance,
+        _: ty::VarianceDiagInfo<'tcx>,
+        a: T,
+        b: T,
+    ) -> RelateResult<'tcx, T> {
+        self.relate(a, b)
+    }
+
+    #[instrument(skip(self), level = "debug")]
+    fn regions(
+        &mut self,
+        pattern: ty::Region<'tcx>,
+        value: ty::Region<'tcx>,
+    ) -> RelateResult<'tcx, ty::Region<'tcx>> {
+        debug!("self.pattern_depth = {:?}", self.pattern_depth);
+        if let ty::RegionKind::ReLateBound(depth, br) = pattern.kind() && depth == self.pattern_depth {
+            self.bind(br, value)
+        } else if pattern == value {
+            Ok(pattern)
+        } else {
+            self.no_match()
+        }
+    }
+
+    #[instrument(skip(self), level = "debug")]
+    fn tys(&mut self, pattern: Ty<'tcx>, value: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
+        if pattern == value { Ok(pattern) } else { relate::super_relate_tys(self, pattern, value) }
+    }
+
+    #[instrument(skip(self), level = "debug")]
+    fn consts(
+        &mut self,
+        pattern: ty::Const<'tcx>,
+        value: ty::Const<'tcx>,
+    ) -> RelateResult<'tcx, ty::Const<'tcx>> {
+        debug!("{}.consts({:?}, {:?})", self.tag(), pattern, value);
+        if pattern == value {
+            Ok(pattern)
+        } else {
+            relate::super_relate_consts(self, pattern, value)
+        }
+    }
+
+    fn binders<T>(
+        &mut self,
+        pattern: ty::Binder<'tcx, T>,
+        value: ty::Binder<'tcx, T>,
+    ) -> RelateResult<'tcx, ty::Binder<'tcx, T>>
+    where
+        T: Relate<'tcx>,
+    {
+        self.pattern_depth.shift_in(1);
+        let result = Ok(pattern.rebind(self.relate(pattern.skip_binder(), value.skip_binder())?));
+        self.pattern_depth.shift_out(1);
+        result
+    }
+}
diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs
index 1c521c9..191f5f1 100644
--- a/compiler/rustc_infer/src/infer/outlives/verify.rs
+++ b/compiler/rustc_infer/src/infer/outlives/verify.rs
@@ -1,4 +1,5 @@
 use crate::infer::outlives::env::RegionBoundPairs;
+use crate::infer::region_constraints::VerifyIfEq;
 use crate::infer::{GenericKind, VerifyBound};
 use rustc_data_structures::captures::Captures;
 use rustc_data_structures::sso::SsoHashSet;
@@ -82,27 +83,39 @@
         debug!("param_bound(param_ty={:?})", param_ty);
 
         // Start with anything like `T: 'a` we can scrape from the
-        // environment
-        let param_bounds = self
-            .declared_generic_bounds_from_env(GenericKind::Param(param_ty))
-            .into_iter()
-            .map(|outlives| outlives.1);
+        // environment. If the environment contains something like
+        // `for<'a> T: 'a`, then we know that `T` outlives everything.
+        let declared_bounds_from_env = self.declared_generic_bounds_from_env(param_ty);
+        let mut param_bounds = vec![];
+        for declared_bound in declared_bounds_from_env {
+            let bound_region = declared_bound.map_bound(|outlives| outlives.1);
+            if let Some(region) = bound_region.no_bound_vars() {
+                // This is `T: 'a` for some free region `'a`.
+                param_bounds.push(VerifyBound::OutlivedBy(region));
+            } else {
+                // This is `for<'a> T: 'a`. This means that `T` outlives everything! All done here.
+                return VerifyBound::AllBounds(vec![]);
+            }
+        }
 
         // Add in the default bound of fn body that applies to all in
         // scope type parameters:
-        let param_bounds = param_bounds.chain(self.implicit_region_bound);
+        if let Some(r) = self.implicit_region_bound {
+            param_bounds.push(VerifyBound::OutlivedBy(r));
+        }
 
-        let any_bounds: Vec<_> = param_bounds.map(|r| VerifyBound::OutlivedBy(r)).collect();
-
-        if any_bounds.is_empty() {
+        if param_bounds.is_empty() {
             // We know that all types `T` outlive `'empty`, so if we
             // can find no other bound, then check that the region
             // being tested is `'empty`.
             VerifyBound::IsEmpty
+        } else if param_bounds.len() == 1 {
+            // Micro-opt: no need to store the vector if it's just len 1
+            param_bounds.pop().unwrap()
         } else {
             // If we can find any other bound `R` such that `T: R`, then
             // we don't need to check for `'empty`, because `R: 'empty`.
-            VerifyBound::AnyBound(any_bounds)
+            VerifyBound::AnyBound(param_bounds)
         }
     }
 
@@ -122,17 +135,10 @@
     pub fn projection_approx_declared_bounds_from_env(
         &self,
         projection_ty: ty::ProjectionTy<'tcx>,
-    ) -> Vec<ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>> {
+    ) -> Vec<ty::Binder<'tcx, ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>>> {
         let projection_ty = GenericKind::Projection(projection_ty).to_ty(self.tcx);
         let erased_projection_ty = self.tcx.erase_regions(projection_ty);
-        self.declared_generic_bounds_from_env_with_compare_fn(|ty| {
-            if let ty::Projection(..) = ty.kind() {
-                let erased_ty = self.tcx.erase_regions(ty);
-                erased_ty == erased_projection_ty
-            } else {
-                false
-            }
-        })
+        self.declared_generic_bounds_from_env_for_erased_ty(erased_projection_ty)
     }
 
     /// Searches the where-clauses in scope for regions that
@@ -159,15 +165,15 @@
         let env_bounds = self
             .projection_approx_declared_bounds_from_env(projection_ty)
             .into_iter()
-            .map(|ty::OutlivesPredicate(ty, r)| {
-                let vb = VerifyBound::OutlivedBy(r);
-                if ty == projection_ty_as_ty {
+            .map(|binder| {
+                if let Some(ty::OutlivesPredicate(ty, r)) = binder.no_bound_vars() && ty == projection_ty_as_ty {
                     // Micro-optimize if this is an exact match (this
                     // occurs often when there are no region variables
                     // involved).
-                    vb
+                    VerifyBound::OutlivedBy(r)
                 } else {
-                    VerifyBound::IfEq(ty, Box::new(vb))
+                    let verify_if_eq_b = binder.map_bound(|ty::OutlivesPredicate(ty, bound)| VerifyIfEq { ty, bound });
+                    VerifyBound::IfEq(verify_if_eq_b)
                 }
             });
 
@@ -219,26 +225,34 @@
     /// bounds, but all the bounds it returns can be relied upon.
     fn declared_generic_bounds_from_env(
         &self,
-        generic: GenericKind<'tcx>,
-    ) -> Vec<ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>> {
-        let generic_ty = generic.to_ty(self.tcx);
-        self.declared_generic_bounds_from_env_with_compare_fn(|ty| ty == generic_ty)
+        param_ty: ty::ParamTy,
+    ) -> Vec<ty::Binder<'tcx, ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>>> {
+        let generic_ty = param_ty.to_ty(self.tcx);
+        self.declared_generic_bounds_from_env_for_erased_ty(generic_ty)
     }
 
-    fn declared_generic_bounds_from_env_with_compare_fn(
+    /// Searches the environment to find all bounds that apply to `erased_ty`.
+    /// Obviously these must be approximate -- they are in fact both *over* and
+    /// and *under* approximated:
+    ///
+    /// * Over-approximated because we erase regions, so
+    /// * Under-approximated because we look for syntactic equality and so for complex types
+    ///   like `<T as Foo<fn(&u32, &u32)>>::Item` or whatever we may fail to figure out
+    ///   all the subtleties.
+    ///
+    /// In some cases, such as when `erased_ty` represents a `ty::Param`, however,
+    /// the result is precise.
+    fn declared_generic_bounds_from_env_for_erased_ty(
         &self,
-        compare_ty: impl Fn(Ty<'tcx>) -> bool,
-    ) -> Vec<ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>> {
+        erased_ty: Ty<'tcx>,
+    ) -> Vec<ty::Binder<'tcx, ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>>> {
         let tcx = self.tcx;
 
         // To start, collect bounds from user environment. Note that
         // parameter environments are already elaborated, so we don't
-        // have to worry about that. Comparing using `==` is a bit
-        // dubious for projections, but it will work for simple cases
-        // like `T` and `T::Item`. It may not work as well for things
-        // like `<T as Foo<'a>>::Item`.
+        // have to worry about that.
         let c_b = self.param_env.caller_bounds();
-        let param_bounds = self.collect_outlives_from_predicate_list(&compare_ty, c_b.into_iter());
+        let param_bounds = self.collect_outlives_from_predicate_list(erased_ty, c_b.into_iter());
 
         // Next, collect regions we scraped from the well-formedness
         // constraints in the fn signature. To do that, we walk the list
@@ -253,18 +267,20 @@
         // don't know that this holds from first principles.
         let from_region_bound_pairs = self.region_bound_pairs.iter().filter_map(|&(r, p)| {
             debug!(
-                "declared_generic_bounds_from_env_with_compare_fn: region_bound_pair = {:?}",
+                "declared_generic_bounds_from_env_for_erased_ty: region_bound_pair = {:?}",
                 (r, p)
             );
             let p_ty = p.to_ty(tcx);
-            compare_ty(p_ty).then_some(ty::OutlivesPredicate(p_ty, r))
+            let erased_p_ty = self.tcx.erase_regions(p_ty);
+            (erased_p_ty == erased_ty)
+                .then_some(ty::Binder::dummy(ty::OutlivesPredicate(p.to_ty(tcx), r)))
         });
 
         param_bounds
             .chain(from_region_bound_pairs)
             .inspect(|bound| {
                 debug!(
-                    "declared_generic_bounds_from_env_with_compare_fn: result predicate = {:?}",
+                    "declared_generic_bounds_from_env_for_erased_ty: result predicate = {:?}",
                     bound
                 )
             })
@@ -344,12 +360,19 @@
     /// otherwise want a precise match.
     fn collect_outlives_from_predicate_list(
         &self,
-        compare_ty: impl Fn(Ty<'tcx>) -> bool,
+        erased_ty: Ty<'tcx>,
         predicates: impl Iterator<Item = ty::Predicate<'tcx>>,
-    ) -> impl Iterator<Item = ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>> {
-        predicates
-            .filter_map(|p| p.to_opt_type_outlives())
-            .filter_map(|p| p.no_bound_vars())
-            .filter(move |p| compare_ty(p.0))
+    ) -> impl Iterator<Item = ty::Binder<'tcx, ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>>>
+    {
+        let tcx = self.tcx;
+        let param_env = self.param_env;
+        predicates.filter_map(|p| p.to_opt_type_outlives()).filter(move |outlives_predicate| {
+            super::test_type_match::can_match_erased_ty(
+                tcx,
+                param_env,
+                *outlives_predicate,
+                erased_ty,
+            )
+        })
     }
 }
diff --git a/compiler/rustc_infer/src/infer/region_constraints/mod.rs b/compiler/rustc_infer/src/infer/region_constraints/mod.rs
index efe2543..19f83e3 100644
--- a/compiler/rustc_infer/src/infer/region_constraints/mod.rs
+++ b/compiler/rustc_infer/src/infer/region_constraints/mod.rs
@@ -190,41 +190,8 @@
 /// This is described with an `AnyRegion('a, 'b)` node.
 #[derive(Debug, Clone)]
 pub enum VerifyBound<'tcx> {
-    /// Given a kind K and a bound B, expands to a function like the
-    /// following, where `G` is the generic for which this verify
-    /// bound was created:
-    ///
-    /// ```ignore (pseudo-rust)
-    /// fn(min) -> bool {
-    ///     if G == K {
-    ///         B(min)
-    ///     } else {
-    ///         false
-    ///     }
-    /// }
-    /// ```
-    ///
-    /// In other words, if the generic `G` that we are checking is
-    /// equal to `K`, then check the associated verify bound
-    /// (otherwise, false).
-    ///
-    /// This is used when we have something in the environment that
-    /// may or may not be relevant, depending on the region inference
-    /// results. For example, we may have `where <T as
-    /// Trait<'a>>::Item: 'b` in our where-clauses. If we are
-    /// generating the verify-bound for `<T as Trait<'0>>::Item`, then
-    /// this where-clause is only relevant if `'0` winds up inferred
-    /// to `'a`.
-    ///
-    /// So we would compile to a verify-bound like
-    ///
-    /// ```ignore (illustrative)
-    /// IfEq(<T as Trait<'a>>::Item, AnyRegion('a))
-    /// ```
-    ///
-    /// meaning, if the subject G is equal to `<T as Trait<'a>>::Item`
-    /// (after inference), and `'a: min`, then `G: min`.
-    IfEq(Ty<'tcx>, Box<VerifyBound<'tcx>>),
+    /// See [`VerifyIfEq`] docs
+    IfEq(ty::Binder<'tcx, VerifyIfEq<'tcx>>),
 
     /// Given a region `R`, expands to the function:
     ///
@@ -267,6 +234,53 @@
     AllBounds(Vec<VerifyBound<'tcx>>),
 }
 
+/// This is a "conditional bound" that checks the result of inference
+/// and supplies a bound if it ended up being relevant. It's used in situations
+/// like this:
+///
+/// ```rust
+/// fn foo<'a, 'b, T: SomeTrait<'a>>
+/// where
+///    <T as SomeTrait<'a>>::Item: 'b
+/// ```
+///
+/// If we have an obligation like `<T as SomeTrait<'?x>>::Item: 'c`, then
+/// we don't know yet whether it suffices to show that `'b: 'c`. If `'?x` winds
+/// up being equal to `'a`, then the where-clauses on function applies, and
+/// in that case we can show `'b: 'c`. But if `'?x` winds up being something
+/// else, the bound isn't relevant.
+///
+/// In the [`VerifyBound`], this struct is enclosed in `Binder to account
+/// for cases like
+///
+/// ```rust
+/// where for<'a> <T as SomeTrait<'a>::Item: 'a
+/// ```
+///
+/// The idea is that we have to find some instantiation of `'a` that can
+/// make `<T as SomeTrait<'a>>::Item` equal to the final value of `G`,
+/// the generic we are checking.
+///
+/// ```ignore (pseudo-rust)
+/// fn(min) -> bool {
+///     exists<'a> {
+///         if G == K {
+///             B(min)
+///         } else {
+///             false
+///         }
+///     }
+/// }
+/// ```
+#[derive(Debug, Copy, Clone, TypeFoldable)]
+pub struct VerifyIfEq<'tcx> {
+    /// Type which must match the generic `G`
+    pub ty: Ty<'tcx>,
+
+    /// Bound that applies if `ty` is equal.
+    pub bound: Region<'tcx>,
+}
+
 #[derive(Copy, Clone, PartialEq, Eq, Hash)]
 pub(crate) struct TwoRegions<'tcx> {
     a: Region<'tcx>,
@@ -770,7 +784,7 @@
 
     pub fn cannot_hold(&self) -> bool {
         match self {
-            VerifyBound::IfEq(_, b) => b.cannot_hold(),
+            VerifyBound::IfEq(..) => false,
             VerifyBound::IsEmpty => false,
             VerifyBound::OutlivedBy(_) => false,
             VerifyBound::AnyBound(bs) => bs.iter().all(|b| b.cannot_hold()),
diff --git a/compiler/rustc_infer/src/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs
index cf93451..d830000b 100644
--- a/compiler/rustc_infer/src/infer/resolve.rs
+++ b/compiler/rustc_infer/src/infer/resolve.rs
@@ -1,7 +1,7 @@
 use super::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use super::{FixupError, FixupResult, InferCtxt, Span};
 use rustc_middle::mir;
-use rustc_middle::ty::fold::{FallibleTypeFolder, TypeFolder, TypeVisitor};
+use rustc_middle::ty::fold::{FallibleTypeFolder, TypeFolder, TypeSuperFoldable, TypeVisitor};
 use rustc_middle::ty::{self, Const, InferConst, Ty, TyCtxt, TypeFoldable};
 
 use std::ops::ControlFlow;
@@ -223,7 +223,7 @@
             Ok(c) // micro-optimize -- if there is nothing in this const that this fold affects...
         } else {
             let c = self.infcx.shallow_resolve(c);
-            match c.val() {
+            match c.kind() {
                 ty::ConstKind::Infer(InferConst::Var(vid)) => {
                     return Err(FixupError::UnresolvedConst(vid));
                 }
diff --git a/compiler/rustc_infer/src/infer/sub.rs b/compiler/rustc_infer/src/infer/sub.rs
index 3600b54..d0c6d8d 100644
--- a/compiler/rustc_infer/src/infer/sub.rs
+++ b/compiler/rustc_infer/src/infer/sub.rs
@@ -198,7 +198,8 @@
     where
         T: Relate<'tcx>,
     {
-        self.fields.higher_ranked_sub(a, b, self.a_is_expected)
+        self.fields.higher_ranked_sub(a, b, self.a_is_expected)?;
+        Ok(a)
     }
 }
 
diff --git a/compiler/rustc_infer/src/infer/undo_log.rs b/compiler/rustc_infer/src/infer/undo_log.rs
index 1b696f2..74a26eb 100644
--- a/compiler/rustc_infer/src/infer/undo_log.rs
+++ b/compiler/rustc_infer/src/infer/undo_log.rs
@@ -185,6 +185,10 @@
         })
     }
 
+    pub(crate) fn opaque_types_in_snapshot(&self, s: &Snapshot<'tcx>) -> bool {
+        self.logs[s.undo_len..].iter().any(|log| matches!(log, UndoLog::OpaqueTypes(..)))
+    }
+
     pub(crate) fn region_constraints(
         &self,
     ) -> impl Iterator<Item = &'_ region_constraints::UndoLog<'tcx>> + Clone {
diff --git a/compiler/rustc_infer/src/lib.rs b/compiler/rustc_infer/src/lib.rs
index 4c691c2..7769a68 100644
--- a/compiler/rustc_infer/src/lib.rs
+++ b/compiler/rustc_infer/src/lib.rs
@@ -16,13 +16,13 @@
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![feature(box_patterns)]
 #![feature(control_flow_enum)]
-#![cfg_attr(bootstrap, feature(derive_default_enum))]
 #![feature(extend_one)]
 #![feature(label_break_value)]
 #![feature(let_chains)]
 #![feature(let_else)]
 #![feature(min_specialization)]
 #![feature(never_type)]
+#![feature(try_blocks)]
 #![recursion_limit = "512"] // For rustdoc
 
 #[macro_use]
diff --git a/compiler/rustc_infer/src/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs
index 85bb727..4df4de2 100644
--- a/compiler/rustc_infer/src/traits/mod.rs
+++ b/compiler/rustc_infer/src/traits/mod.rs
@@ -69,7 +69,7 @@
     }
 }
 
-impl TraitObligation<'_> {
+impl<'tcx> TraitObligation<'tcx> {
     /// Returns `true` if the trait predicate is considered `const` in its ParamEnv.
     pub fn is_const(&self) -> bool {
         match (self.predicate.skip_binder().constness, self.param_env.constness()) {
@@ -77,6 +77,13 @@
             _ => false,
         }
     }
+
+    pub fn derived_cause(
+        &self,
+        variant: impl FnOnce(DerivedObligationCause<'tcx>) -> ObligationCauseCode<'tcx>,
+    ) -> ObligationCause<'tcx> {
+        self.cause.clone().derived_cause(self.predicate, variant)
+    }
 }
 
 // `PredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger.
diff --git a/compiler/rustc_infer/src/traits/project.rs b/compiler/rustc_infer/src/traits/project.rs
index b84ed3d..1846920 100644
--- a/compiler/rustc_infer/src/traits/project.rs
+++ b/compiler/rustc_infer/src/traits/project.rs
@@ -203,7 +203,7 @@
             Some(&ProjectionCacheEntry::NormalizedTy { ref ty, complete: _ }) => {
                 info!("ProjectionCacheEntry::complete({:?}) - completing {:?}", key, ty);
                 let mut ty = ty.clone();
-                if result == EvaluationResult::EvaluatedToOk {
+                if result.must_apply_considering_regions() {
                     ty.obligations = vec![];
                 }
                 map.insert(key, ProjectionCacheEntry::NormalizedTy { ty, complete: Some(result) });
diff --git a/compiler/rustc_infer/src/traits/structural_impls.rs b/compiler/rustc_infer/src/traits/structural_impls.rs
index 20453ee..82ee4bb 100644
--- a/compiler/rustc_infer/src/traits/structural_impls.rs
+++ b/compiler/rustc_infer/src/traits/structural_impls.rs
@@ -60,10 +60,7 @@
 // TypeFoldable implementations.
 
 impl<'tcx, O: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::Obligation<'tcx, O> {
-    fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
-        self,
-        folder: &mut F,
-    ) -> Result<Self, F::Error> {
+    fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
         Ok(traits::Obligation {
             cause: self.cause,
             recursion_depth: self.recursion_depth,
@@ -72,7 +69,7 @@
         })
     }
 
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         self.predicate.visit_with(visitor)?;
         self.param_env.visit_with(visitor)
     }
diff --git a/compiler/rustc_interface/Cargo.toml b/compiler/rustc_interface/Cargo.toml
index 29d1cd0..26b1b99 100644
--- a/compiler/rustc_interface/Cargo.toml
+++ b/compiler/rustc_interface/Cargo.toml
@@ -7,11 +7,10 @@
 doctest = false
 
 [dependencies]
-libc = "0.2"
 libloading = "0.7.1"
 tracing = "0.1"
-rustc-rayon-core = { version = "0.3.2", optional = true }
-rayon = { version = "0.3.2", package = "rustc-rayon", optional = true }
+rustc-rayon-core = { version = "0.4.0", optional = true }
+rayon = { version = "0.4.0", package = "rustc-rayon", optional = true }
 smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
 rustc_ast = { path = "../rustc_ast" }
 rustc_attr = { path = "../rustc_attr" }
@@ -49,6 +48,9 @@
 rustc_ty_utils = { path = "../rustc_ty_utils" }
 tempfile = "3.2"
 
+[target.'cfg(unix)'.dependencies]
+libc = "0.2"
+
 [target.'cfg(windows)'.dependencies]
 winapi = { version = "0.3", features = ["libloaderapi"] }
 
diff --git a/compiler/rustc_interface/src/callbacks.rs b/compiler/rustc_interface/src/callbacks.rs
index a18e2d1..76442de 100644
--- a/compiler/rustc_interface/src/callbacks.rs
+++ b/compiler/rustc_interface/src/callbacks.rs
@@ -24,7 +24,7 @@
 }
 
 /// This is a callback from `rustc_ast` as it cannot access the implicit state
-/// in `rustc_middle` otherwise. It is used to when diagnostic messages are
+/// in `rustc_middle` otherwise. It is used when diagnostic messages are
 /// emitted and stores them in the current query, if there is one.
 fn track_diagnostic(diagnostic: &Diagnostic) {
     tls::with_context_opt(|icx| {
diff --git a/compiler/rustc_interface/src/lib.rs b/compiler/rustc_interface/src/lib.rs
index 40e02f4..d443057 100644
--- a/compiler/rustc_interface/src/lib.rs
+++ b/compiler/rustc_interface/src/lib.rs
@@ -2,7 +2,6 @@
 #![feature(let_else)]
 #![feature(internal_output_capture)]
 #![feature(thread_spawn_unchecked)]
-#![feature(nll)]
 #![feature(once_cell)]
 #![recursion_limit = "256"]
 #![allow(rustc::potential_query_instability)]
diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs
index 0011926..502afa4 100644
--- a/compiler/rustc_interface/src/passes.rs
+++ b/compiler/rustc_interface/src/passes.rs
@@ -13,6 +13,7 @@
 use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan, PResult};
 use rustc_expand::base::{ExtCtxt, LintStoreExpand, ResolverExpand};
 use rustc_hir::def_id::{StableCrateId, LOCAL_CRATE};
+use rustc_hir::definitions::Definitions;
 use rustc_hir::Crate;
 use rustc_lint::{EarlyCheckNode, LintStore};
 use rustc_metadata::creader::CStore;
@@ -20,16 +21,15 @@
 use rustc_middle::arena::Arena;
 use rustc_middle::dep_graph::DepGraph;
 use rustc_middle::ty::query::{ExternProviders, Providers};
-use rustc_middle::ty::{self, GlobalCtxt, RegisteredTools, ResolverOutputs, TyCtxt};
+use rustc_middle::ty::{self, GlobalCtxt, RegisteredTools, TyCtxt};
 use rustc_mir_build as mir_build;
 use rustc_parse::{parse_crate_from_file, parse_crate_from_source_str, validate_attr};
 use rustc_passes::{self, hir_stats, layout_test};
 use rustc_plugin_impl as plugin;
 use rustc_query_impl::{OnDiskCache, Queries as TcxQueries};
 use rustc_resolve::{Resolver, ResolverArenas};
-use rustc_serialize::json;
 use rustc_session::config::{CrateType, Input, OutputFilenames, OutputType};
-use rustc_session::cstore::{MetadataLoader, MetadataLoaderDyn};
+use rustc_session::cstore::{CrateStoreDyn, MetadataLoader, MetadataLoaderDyn};
 use rustc_session::output::{filename_for_input, filename_for_metadata};
 use rustc_session::search_paths::PathKind;
 use rustc_session::{Limit, Session};
@@ -44,11 +44,11 @@
 use std::cell::RefCell;
 use std::ffi::OsString;
 use std::io::{self, BufWriter, Write};
-use std::lazy::SyncLazy;
 use std::marker::PhantomPinned;
 use std::path::{Path, PathBuf};
 use std::pin::Pin;
 use std::rc::Rc;
+use std::sync::LazyLock;
 use std::{env, fs, iter};
 
 pub fn parse<'a>(sess: &'a Session, input: &Input) -> PResult<'a, ast::Crate> {
@@ -59,10 +59,6 @@
         }
     })?;
 
-    if sess.opts.debugging_opts.ast_json_noexpand {
-        println!("{}", json::as_json(&krate));
-    }
-
     if sess.opts.debugging_opts.input_stats {
         eprintln!("Lines of code:             {}", sess.source_map().count_lines());
         eprintln!("Pre-expansion node count:  {}", count_nodes(&krate));
@@ -141,7 +137,10 @@
             f((&mut *resolver).as_mut().unwrap())
         }
 
-        pub fn to_resolver_outputs(resolver: Rc<RefCell<BoxedResolver>>) -> ResolverOutputs {
+        pub fn to_resolver_outputs(
+            resolver: Rc<RefCell<BoxedResolver>>,
+        ) -> (Definitions, Box<CrateStoreDyn>, ty::ResolverOutputs, ty::ResolverAstLowering)
+        {
             match Rc::try_unwrap(resolver) {
                 Ok(resolver) => {
                     let mut resolver = resolver.into_inner();
@@ -423,10 +422,6 @@
         hir_stats::print_ast_stats(&krate, "POST EXPANSION AST STATS");
     }
 
-    if sess.opts.debugging_opts.ast_json {
-        println!("{}", json::as_json(&krate));
-    }
-
     resolver.resolve_crate(&krate);
 
     // Needs to go *after* expansion to be able to check the results of macro expansion.
@@ -458,7 +453,7 @@
                     .span_suggestion(
                         first_span,
                         "try using their name instead",
-                        "ferris".to_string(),
+                        "ferris",
                         Applicability::MaybeIncorrect,
                     )
                     .emit();
@@ -487,18 +482,23 @@
     Ok(krate)
 }
 
-pub fn lower_to_hir<'res, 'tcx>(
-    sess: &'tcx Session,
-    resolver: &'res mut Resolver<'_>,
+fn lower_to_hir<'tcx>(
+    sess: &Session,
+    definitions: &mut Definitions,
+    cstore: &CrateStoreDyn,
+    resolutions: &ty::ResolverOutputs,
+    resolver: ty::ResolverAstLowering,
     krate: Rc<ast::Crate>,
     arena: &'tcx rustc_ast_lowering::Arena<'tcx>,
 ) -> &'tcx Crate<'tcx> {
     // Lower AST to HIR.
     let hir_crate = rustc_ast_lowering::lower_crate(
         sess,
-        &*krate,
+        &krate,
+        definitions,
+        cstore,
+        resolutions,
         resolver,
-        rustc_parse::nt_to_tokenstream,
         arena,
     );
 
@@ -774,7 +774,7 @@
     Ok(outputs)
 }
 
-pub static DEFAULT_QUERY_PROVIDERS: SyncLazy<Providers> = SyncLazy::new(|| {
+pub static DEFAULT_QUERY_PROVIDERS: LazyLock<Providers> = LazyLock::new(|| {
     let providers = &mut Providers::default();
     providers.analysis = analysis;
     proc_macro_decls::provide(providers);
@@ -799,7 +799,7 @@
     *providers
 });
 
-pub static DEFAULT_EXTERN_QUERY_PROVIDERS: SyncLazy<ExternProviders> = SyncLazy::new(|| {
+pub static DEFAULT_EXTERN_QUERY_PROVIDERS: LazyLock<ExternProviders> = LazyLock::new(|| {
     let mut extern_providers = ExternProviders::default();
     rustc_metadata::provide_extern(&mut extern_providers);
     rustc_codegen_ssa::provide_extern(&mut extern_providers);
@@ -838,10 +838,21 @@
     // incr. comp. yet.
     dep_graph.assert_ignored();
 
+    let (mut definitions, cstore, resolver_outputs, resolver_for_lowering) =
+        BoxedResolver::to_resolver_outputs(resolver);
+
     let sess = &compiler.session();
-    let krate =
-        resolver.borrow_mut().access(|resolver| lower_to_hir(sess, resolver, krate, hir_arena));
-    let resolver_outputs = BoxedResolver::to_resolver_outputs(resolver);
+
+    // Lower AST to HIR.
+    let krate = lower_to_hir(
+        sess,
+        &mut definitions,
+        &*cstore,
+        &resolver_outputs,
+        resolver_for_lowering,
+        krate,
+        hir_arena,
+    );
 
     let query_result_on_disk_cache = rustc_incremental::load_query_result_cache(sess);
 
@@ -866,6 +877,8 @@
                 sess,
                 lint_store,
                 arena,
+                definitions,
+                cstore,
                 resolver_outputs,
                 krate,
                 dep_graph,
@@ -943,7 +956,6 @@
                         //
                         // maybe move the check to a MIR pass?
                         tcx.ensure().check_mod_liveness(module);
-                        tcx.ensure().check_mod_intrinsics(module);
                     });
                 });
             }
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index 1327bf6..30a29ed 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -644,9 +644,6 @@
     // Make sure that changing an [UNTRACKED] option leaves the hash unchanged.
     // This list is in alphabetical order.
     untracked!(assert_incr_state, Some(String::from("loaded")));
-    untracked!(ast_json, true);
-    untracked!(ast_json_noexpand, true);
-    untracked!(borrowck, String::from("other"));
     untracked!(deduplicate_diagnostics, false);
     untracked!(dep_tasks, true);
     untracked!(dlltool, Some(PathBuf::from("custom_dlltool.exe")));
@@ -792,6 +789,7 @@
     tracked!(thinlto, Some(true));
     tracked!(thir_unsafeck, true);
     tracked!(tls_model, Some(TlsModel::GeneralDynamic));
+    tracked!(translate_remapped_path_to_local_path, false);
     tracked!(trap_unreachable, Some(false));
     tracked!(treat_err_as_bug, NonZeroUsize::new(1));
     tracked!(tune_cpu, Some(String::from("abc")));
@@ -799,6 +797,7 @@
     tracked!(unleash_the_miri_inside_of_you, true);
     tracked!(use_ctors_section, Some(true));
     tracked!(verify_llvm_ir, true);
+    tracked!(virtual_function_elimination, true);
     tracked!(wasi_exec_model, Some(WasiExecModel::Reactor));
 
     macro_rules! tracked_no_crate_hash {
diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs
index 3fa8017..fb9258e 100644
--- a/compiler/rustc_interface/src/util.rs
+++ b/compiler/rustc_interface/src/util.rs
@@ -24,12 +24,12 @@
 use rustc_span::symbol::{sym, Symbol};
 use std::env;
 use std::env::consts::{DLL_PREFIX, DLL_SUFFIX};
-use std::lazy::SyncOnceCell;
 use std::mem;
 #[cfg(not(parallel_compiler))]
 use std::panic;
 use std::path::{Path, PathBuf};
 use std::sync::atomic::{AtomicBool, Ordering};
+use std::sync::OnceLock;
 use std::thread;
 use tracing::info;
 
@@ -242,7 +242,7 @@
     maybe_sysroot: &Option<PathBuf>,
     backend_name: Option<&str>,
 ) -> Box<dyn CodegenBackend> {
-    static LOAD: SyncOnceCell<unsafe fn() -> Box<dyn CodegenBackend>> = SyncOnceCell::new();
+    static LOAD: OnceLock<unsafe fn() -> Box<dyn CodegenBackend>> = OnceLock::new();
 
     let load = LOAD.get_or_init(|| {
         let default_codegen_backend = option_env!("CFG_DEFAULT_CODEGEN_BACKEND").unwrap_or("llvm");
@@ -265,7 +265,7 @@
 // loading, so we leave the code here. It is potentially useful for other tools
 // that want to invoke the rustc binary while linking to rustc as well.
 pub fn rustc_path<'a>() -> Option<&'a Path> {
-    static RUSTC_PATH: SyncOnceCell<Option<PathBuf>> = SyncOnceCell::new();
+    static RUSTC_PATH: OnceLock<Option<PathBuf>> = OnceLock::new();
 
     const BIN_PATH: &str = env!("RUSTC_INSTALL_BINDIR");
 
diff --git a/compiler/rustc_lint/Cargo.toml b/compiler/rustc_lint/Cargo.toml
index 02f747e..fab60b6 100644
--- a/compiler/rustc_lint/Cargo.toml
+++ b/compiler/rustc_lint/Cargo.toml
@@ -21,3 +21,4 @@
 rustc_trait_selection = { path = "../rustc_trait_selection" }
 rustc_parse_format = { path = "../rustc_parse_format" }
 rustc_infer = { path = "../rustc_infer" }
+rustc_type_ir = { path = "../rustc_type_ir" }
diff --git a/compiler/rustc_lint/src/array_into_iter.rs b/compiler/rustc_lint/src/array_into_iter.rs
index dff2e31..b33ab40 100644
--- a/compiler/rustc_lint/src/array_into_iter.rs
+++ b/compiler/rustc_lint/src/array_into_iter.rs
@@ -136,7 +136,7 @@
                     diag.span_suggestion(
                         receiver_arg.span.shrink_to_hi().to(expr.span.shrink_to_hi()),
                         "or remove `.into_iter()` to iterate by value",
-                        String::new(),
+                        "",
                         Applicability::MaybeIncorrect,
                     );
                 } else if receiver_ty.is_array() {
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index a87083a..8266f15 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -338,6 +338,17 @@
                 .emit();
         })
     }
+
+    fn report_overridden_symbol_section(&self, cx: &EarlyContext<'_>, span: Span, msg: &str) {
+        self.report_unsafe(cx, span, |lint| {
+            lint.build(msg)
+                .note(
+                    "the program's behavior with overridden link sections on items is unpredictable \
+                    and Rust cannot provide guarantees when you manually override them",
+                )
+                .emit();
+        })
+    }
 }
 
 impl EarlyLintPass for UnsafeCode {
@@ -385,6 +396,7 @@
                         "declaration of a `no_mangle` function",
                     );
                 }
+
                 if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::export_name) {
                     self.report_overridden_symbol_name(
                         cx,
@@ -392,6 +404,14 @@
                         "declaration of a function with `export_name`",
                     );
                 }
+
+                if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::link_section) {
+                    self.report_overridden_symbol_section(
+                        cx,
+                        attr.span,
+                        "declaration of a function with `link_section`",
+                    );
+                }
             }
 
             ast::ItemKind::Static(..) => {
@@ -402,6 +422,7 @@
                         "declaration of a `no_mangle` static",
                     );
                 }
+
                 if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::export_name) {
                     self.report_overridden_symbol_name(
                         cx,
@@ -409,6 +430,14 @@
                         "declaration of a static with `export_name`",
                     );
                 }
+
+                if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::link_section) {
+                    self.report_overridden_symbol_section(
+                        cx,
+                        attr.span,
+                        "declaration of a static with `link_section`",
+                    );
+                }
             }
 
             _ => {}
@@ -964,7 +993,7 @@
             .span_suggestion_short(
                 attr.span,
                 suggestion.unwrap_or("remove this attribute"),
-                String::new(),
+                "",
                 Applicability::MachineApplicable,
             )
             .emit();
@@ -1153,7 +1182,7 @@
                                 .span_suggestion_short(
                                     no_mangle_attr.span,
                                     "remove this attribute",
-                                    String::new(),
+                                    "",
                                     // Use of `#[no_mangle]` suggests FFI intent; correct
                                     // fix may be to monomorphize source by hand
                                     Applicability::MaybeIncorrect,
@@ -1192,7 +1221,7 @@
                         err.span_suggestion(
                             const_span,
                             "try a static value",
-                            "pub static".to_owned(),
+                            "pub static",
                             Applicability::MachineApplicable,
                         );
                         err.emit();
@@ -1252,7 +1281,6 @@
 
 impl<'tcx> LateLintPass<'tcx> for MutableTransmutes {
     fn check_expr(&mut self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) {
-        use rustc_target::spec::abi::Abi::RustIntrinsic;
         if let Some((&ty::Ref(_, _, from_mt), &ty::Ref(_, _, to_mt))) =
             get_transmute_from_to(cx, expr).map(|(ty1, ty2)| (ty1.kind(), ty2.kind()))
         {
@@ -1287,8 +1315,7 @@
         }
 
         fn def_id_is_transmute(cx: &LateContext<'_>, def_id: DefId) -> bool {
-            cx.tcx.fn_sig(def_id).abi() == RustIntrinsic
-                && cx.tcx.item_name(def_id) == sym::transmute
+            cx.tcx.is_intrinsic(def_id) && cx.tcx.item_name(def_id) == sym::transmute
         }
     }
 }
@@ -1374,17 +1401,11 @@
             let def_span = cx.tcx.sess.source_map().guess_head_span(span);
             cx.struct_span_lint(UNREACHABLE_PUB, def_span, |lint| {
                 let mut err = lint.build(&format!("unreachable `pub` {}", what));
-                let replacement = if cx.tcx.features().crate_visibility_modifier {
-                    "crate"
-                } else {
-                    "pub(crate)"
-                }
-                .to_owned();
 
                 err.span_suggestion(
                     vis_span,
                     "consider restricting its visibility",
-                    replacement,
+                    "pub(crate)",
                     applicability,
                 );
                 if exportable {
@@ -1545,7 +1566,7 @@
                 err.span_suggestion(
                     type_alias_generics.where_clause_span,
                     "the clause will not be checked when the type alias is used, and should be removed",
-                    String::new(),
+                    "",
                     Applicability::MachineApplicable,
                 );
                 if !suggested_changing_assoc_types {
@@ -1589,13 +1610,11 @@
             hir::ItemKind::Const(_, body_id) => {
                 let def_id = cx.tcx.hir().body_owner_def_id(body_id).to_def_id();
                 // trigger the query once for all constants since that will already report the errors
-                // FIXME: Use ensure here
-                let _ = cx.tcx.const_eval_poly(def_id);
+                cx.tcx.ensure().const_eval_poly(def_id);
             }
             hir::ItemKind::Static(_, _, body_id) => {
                 let def_id = cx.tcx.hir().body_owner_def_id(body_id).to_def_id();
-                // FIXME: Use ensure here
-                let _ = cx.tcx.eval_static_initializer(def_id);
+                cx.tcx.ensure().eval_static_initializer(def_id);
             }
             _ => {}
         }
@@ -1809,7 +1828,7 @@
                     });
                 }
             } else {
-                let replace = "..=".to_owned();
+                let replace = "..=";
                 if join.edition() >= Edition::Edition2021 {
                     let mut err =
                         rustc_errors::struct_span_err!(cx.sess(), pat.span, E0783, "{}", msg,);
@@ -2092,7 +2111,6 @@
         tcx: TyCtxt<'tcx>,
         bounds: &hir::GenericBounds<'_>,
         inferred_outlives: &[ty::Region<'tcx>],
-        infer_static: bool,
     ) -> Vec<(usize, Span)> {
         use rustc_middle::middle::resolve_lifetime::Region;
 
@@ -2102,9 +2120,6 @@
             .filter_map(|(i, bound)| {
                 if let hir::GenericBound::Outlives(lifetime) = bound {
                     let is_inferred = match tcx.named_region(lifetime.hir_id) {
-                        Some(Region::Static) if infer_static => {
-                            inferred_outlives.iter().any(|r| matches!(**r, ty::ReStatic))
-                        }
                         Some(Region::EarlyBound(index, ..)) => inferred_outlives.iter().any(|r| {
                             if let ty::ReEarlyBound(ebr) = **r { ebr.index == index } else { false }
                         }),
@@ -2180,7 +2195,6 @@
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
         use rustc_middle::middle::resolve_lifetime::Region;
 
-        let infer_static = cx.tcx.features().infer_static_outlives_requirements;
         let def_id = item.def_id;
         if let hir::ItemKind::Struct(_, ref hir_generics)
         | hir::ItemKind::Enum(_, ref hir_generics)
@@ -2241,12 +2255,8 @@
                     continue;
                 }
 
-                let bound_spans = self.collect_outlives_bound_spans(
-                    cx.tcx,
-                    bounds,
-                    &relevant_lifetimes,
-                    infer_static,
-                );
+                let bound_spans =
+                    self.collect_outlives_bound_spans(cx.tcx, bounds, &relevant_lifetimes);
                 bound_count += bound_spans.len();
 
                 let drop_predicate = bound_spans.len() == bounds.len();
@@ -2272,10 +2282,9 @@
 
             // If all predicates are inferable, drop the entire clause
             // (including the `where`)
-            if hir_generics.has_where_clause && dropped_predicate_count == num_predicates {
-                let where_span = hir_generics
-                    .where_clause_span()
-                    .expect("span of (nonempty) where clause should exist");
+            if hir_generics.has_where_clause_predicates && dropped_predicate_count == num_predicates
+            {
+                let where_span = hir_generics.where_clause_span;
                 // Extend the where clause back to the closing `>` of the
                 // generics, except for tuple struct, which have the `where`
                 // after the fields of the struct.
@@ -2497,7 +2506,7 @@
             ty: Ty<'tcx>,
             init: InitKind,
         ) -> Option<InitError> {
-            use rustc_middle::ty::TyKind::*;
+            use rustc_type_ir::sty::TyKind::*;
             match ty.kind() {
                 // Primitive types that don't like 0 as a value.
                 Ref(..) => Some(("references must be non-null".to_string(), None)),
@@ -2707,7 +2716,7 @@
 }
 
 impl ClashingExternDeclarations {
-    crate fn new() -> Self {
+    pub(crate) fn new() -> Self {
         ClashingExternDeclarations { seen_decls: FxHashMap::default() }
     }
     /// Insert a new foreign item into the seen set. If a symbol with the same name already exists
@@ -2809,7 +2818,7 @@
                 true
             } else {
                 // Do a full, depth-first comparison between the two.
-                use rustc_middle::ty::TyKind::*;
+                use rustc_type_ir::sty::TyKind::*;
                 let a_kind = a.kind();
                 let b_kind = b.kind();
 
@@ -2862,7 +2871,7 @@
                         }
                         (Array(a_ty, a_const), Array(b_ty, b_const)) => {
                             // For arrays, we also check the constness of the type.
-                            a_const.val() == b_const.val()
+                            a_const.kind() == b_const.kind()
                                 && structurally_same_type_impl(seen_types, cx, *a_ty, *b_ty, ckind)
                         }
                         (Slice(a_ty), Slice(b_ty)) => {
diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs
index d7cd5ec..eeb66f2 100644
--- a/compiler/rustc_lint/src/context.rs
+++ b/compiler/rustc_lint/src/context.rs
@@ -324,7 +324,7 @@
         registered_tools: &RegisteredTools,
     ) {
         let (tool_name, lint_name_only) = parse_lint_and_tool_name(lint_name);
-        if lint_name_only == crate::WARNINGS.name_lower() && level == Level::ForceWarn {
+        if lint_name_only == crate::WARNINGS.name_lower() && matches!(level, Level::ForceWarn(_)) {
             struct_span_err!(
                 sess,
                 DUMMY_SP,
@@ -375,7 +375,7 @@
                 match level {
                     Level::Allow => "-A",
                     Level::Warn => "-W",
-                    Level::ForceWarn => "--force-warn",
+                    Level::ForceWarn(_) => "--force-warn",
                     Level::Deny => "-D",
                     Level::Forbid => "-F",
                     Level::Expect(_) => {
@@ -718,7 +718,7 @@
                                   the macro must produce the documentation as part of its expansion");
                 }
                 BuiltinLintDiagnostics::PatternsInFnsWithoutBody(span, ident) => {
-                    db.span_suggestion(span, "remove `mut` from the parameter", ident.to_string(), Applicability::MachineApplicable);
+                    db.span_suggestion(span, "remove `mut` from the parameter", ident, Applicability::MachineApplicable);
                 }
                 BuiltinLintDiagnostics::MissingAbi(span, default_abi) => {
                     db.span_label(span, "ABI should be specified here");
@@ -778,7 +778,7 @@
 
                     // Suggest the most probable if we found one
                     if let Some(best_match) = find_best_match_for_name(&possibilities, name, None) {
-                        db.span_suggestion(name_span, "did you mean", format!("{best_match}"), Applicability::MaybeIncorrect);
+                        db.span_suggestion(name_span, "did you mean", best_match, Applicability::MaybeIncorrect);
                     }
                 },
                 BuiltinLintDiagnostics::UnexpectedCfg((name, name_span), Some((value, value_span))) => {
@@ -805,7 +805,7 @@
                     } else {
                         db.note(&format!("no expected value for `{name}`"));
                         if name != sym::feature {
-                            db.span_suggestion(name_span.shrink_to_hi().to(value_span), "remove the value", String::new(), Applicability::MaybeIncorrect);
+                            db.span_suggestion(name_span.shrink_to_hi().to(value_span), "remove the value", "", Applicability::MaybeIncorrect);
                         }
                     }
                 },
@@ -819,6 +819,43 @@
                         "see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information",
                     );
                 },
+                BuiltinLintDiagnostics::SingleUseLifetime {
+                    param_span,
+                    use_span: Some((use_span, elide)),
+                    deletion_span,
+                } => {
+                    debug!(?param_span, ?use_span, ?deletion_span);
+                    db.span_label(param_span, "this lifetime...");
+                    db.span_label(use_span, "...is used only here");
+                    let msg = "elide the single-use lifetime";
+                    let (use_span, replace_lt) = if elide {
+                        let use_span = sess.source_map().span_extend_while(
+                            use_span,
+                            char::is_whitespace,
+                        ).unwrap_or(use_span);
+                        (use_span, String::new())
+                    } else {
+                        (use_span, "'_".to_owned())
+                    };
+                    db.multipart_suggestion(
+                        msg,
+                        vec![(deletion_span, String::new()), (use_span, replace_lt)],
+                        Applicability::MachineApplicable,
+                    );
+                },
+                BuiltinLintDiagnostics::SingleUseLifetime {
+                    param_span: _,
+                    use_span: None,
+                    deletion_span,
+                } => {
+                    debug!(?deletion_span);
+                    db.span_suggestion(
+                        deletion_span,
+                        "elide the unused lifetime",
+                        "",
+                        Applicability::MachineApplicable,
+                    );
+                },
             }
             // Rewrap `db`, and pass control to the user.
             decorate(LintDiagnosticBuilder::new(db));
diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs
index 3ea68ae..5de35dc 100644
--- a/compiler/rustc_lint/src/early.rs
+++ b/compiler/rustc_lint/src/early.rs
@@ -63,20 +63,12 @@
         let push = self.context.builder.push(attrs, is_crate_node, None);
 
         self.check_id(id);
-        self.enter_attrs(attrs);
-        f(self);
-        self.exit_attrs(attrs);
-        self.context.builder.pop(push);
-    }
-
-    fn enter_attrs(&mut self, attrs: &'a [ast::Attribute]) {
         debug!("early context: enter_attrs({:?})", attrs);
         run_early_pass!(self, enter_lint_attrs, attrs);
-    }
-
-    fn exit_attrs(&mut self, attrs: &'a [ast::Attribute]) {
+        f(self);
         debug!("early context: exit_attrs({:?})", attrs);
         run_early_pass!(self, exit_lint_attrs, attrs);
+        self.context.builder.pop(push);
     }
 }
 
@@ -239,6 +231,7 @@
 
     fn visit_generic_param(&mut self, param: &'a ast::GenericParam) {
         run_early_pass!(self, check_generic_param, param);
+        self.check_id(param.id);
         ast_visit::walk_generic_param(self, param);
     }
 
@@ -272,7 +265,7 @@
         });
     }
 
-    fn visit_lifetime(&mut self, lt: &'a ast::Lifetime) {
+    fn visit_lifetime(&mut self, lt: &'a ast::Lifetime, _: ast_visit::LifetimeCtxt) {
         run_early_pass!(self, check_lifetime, lt);
         self.check_id(lt.id);
     }
@@ -423,10 +416,25 @@
     let mut passes: Vec<_> = passes.iter().map(|p| (p)()).collect();
     let mut buffered = lint_buffer.unwrap_or_default();
 
-    if !sess.opts.debugging_opts.no_interleave_lints {
+    if sess.opts.debugging_opts.no_interleave_lints {
+        for (i, pass) in passes.iter_mut().enumerate() {
+            buffered =
+                sess.prof.extra_verbose_generic_activity("run_lint", pass.name()).run(|| {
+                    early_lint_node(
+                        sess,
+                        !pre_expansion && i == 0,
+                        lint_store,
+                        registered_tools,
+                        buffered,
+                        EarlyLintPassObjects { lints: slice::from_mut(pass) },
+                        check_node,
+                    )
+                });
+        }
+    } else {
         buffered = early_lint_node(
             sess,
-            pre_expansion,
+            !pre_expansion,
             lint_store,
             registered_tools,
             buffered,
@@ -445,21 +453,6 @@
                 check_node,
             );
         }
-    } else {
-        for (i, pass) in passes.iter_mut().enumerate() {
-            buffered =
-                sess.prof.extra_verbose_generic_activity("run_lint", pass.name()).run(|| {
-                    early_lint_node(
-                        sess,
-                        pre_expansion && i == 0,
-                        lint_store,
-                        registered_tools,
-                        buffered,
-                        EarlyLintPassObjects { lints: slice::from_mut(pass) },
-                        check_node,
-                    )
-                });
-        }
     }
 
     // All of the buffered lints should have been emitted at this point.
diff --git a/compiler/rustc_lint/src/expect.rs b/compiler/rustc_lint/src/expect.rs
index dc48ac0..95e3125 100644
--- a/compiler/rustc_lint/src/expect.rs
+++ b/compiler/rustc_lint/src/expect.rs
@@ -19,16 +19,16 @@
     let lint_expectations = &tcx.lint_levels(()).lint_expectations;
 
     for (id, expectation) in lint_expectations {
-        if !fulfilled_expectations.contains(id)
-            && tool_filter.map_or(true, |filter| expectation.lint_tool == Some(filter))
-        {
-            // This check will always be true, since `lint_expectations` only
-            // holds stable ids
-            if let LintExpectationId::Stable { hir_id, .. } = id {
+        // This check will always be true, since `lint_expectations` only
+        // holds stable ids
+        if let LintExpectationId::Stable { hir_id, .. } = id {
+            if !fulfilled_expectations.contains(&id)
+                && tool_filter.map_or(true, |filter| expectation.lint_tool == Some(filter))
+            {
                 emit_unfulfilled_expectation_lint(tcx, *hir_id, expectation);
-            } else {
-                unreachable!("at this stage all `LintExpectationId`s are stable");
             }
+        } else {
+            unreachable!("at this stage all `LintExpectationId`s are stable");
         }
     }
 }
diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs
index 27d44da..fadb1c8 100644
--- a/compiler/rustc_lint/src/internal.rs
+++ b/compiler/rustc_lint/src/internal.rs
@@ -5,12 +5,14 @@
 use rustc_ast as ast;
 use rustc_errors::Applicability;
 use rustc_hir::def::Res;
-use rustc_hir::{Expr, ExprKind, GenericArg, Path, PathSegment, QPath};
-use rustc_hir::{HirId, Item, ItemKind, Node, Ty, TyKind};
+use rustc_hir::{def_id::DefId, Expr, ExprKind, GenericArg, PatKind, Path, PathSegment, QPath};
+use rustc_hir::{HirId, Impl, Item, ItemKind, Node, Pat, Ty, TyKind};
 use rustc_middle::ty;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::hygiene::{ExpnKind, MacroKind};
 use rustc_span::symbol::{kw, sym, Symbol};
+use rustc_span::Span;
+use tracing::debug;
 
 declare_tool_lint! {
     pub rustc::DEFAULT_HASH_TYPES,
@@ -46,6 +48,41 @@
     }
 }
 
+/// Helper function for lints that check for expressions with calls and use typeck results to
+/// get the `DefId` and `SubstsRef` of the function.
+fn typeck_results_of_method_fn<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &Expr<'_>,
+) -> Option<(Span, DefId, ty::subst::SubstsRef<'tcx>)> {
+    // FIXME(rustdoc): Lints which use this function use typecheck results which can cause
+    // `rustdoc` to error if there are resolution failures.
+    //
+    // As internal lints are currently always run if there are `unstable_options`, they are added
+    // to the lint store of rustdoc. Internal lints are also not used via the `lint_mod` query.
+    // Crate lints run outside of a query so rustdoc currently doesn't disable them.
+    //
+    // Instead of relying on this, either change crate lints to a query disabled by rustdoc, only
+    // run internal lints if the user is explicitly opting in or figure out a different way to
+    // avoid running lints for rustdoc.
+    if cx.tcx.sess.opts.actually_rustdoc {
+        return None;
+    }
+
+    match expr.kind {
+        ExprKind::MethodCall(segment, _, _)
+            if let Some(def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) =>
+        {
+            Some((segment.ident.span, def_id, cx.typeck_results().node_substs(expr.hir_id)))
+        },
+        _ => {
+            match cx.typeck_results().node_type(expr.hir_id).kind() {
+                &ty::FnDef(def_id, substs) => Some((expr.span, def_id, substs)),
+                _ => None,
+            }
+        }
+    }
+}
+
 declare_tool_lint! {
     pub rustc::POTENTIAL_QUERY_INSTABILITY,
     Allow,
@@ -57,35 +94,7 @@
 
 impl LateLintPass<'_> for QueryStability {
     fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
-        // FIXME(rustdoc): This lint uses typecheck results, causing rustdoc to
-        // error if there are resolution failures.
-        //
-        // As internal lints are currently always run if there are `unstable_options`,
-        // they are added to the lint store of rustdoc. Internal lints are also
-        // not used via the `lint_mod` query. Crate lints run outside of a query
-        // so rustdoc currently doesn't disable them.
-        //
-        // Instead of relying on this, either change crate lints to a query disabled by
-        // rustdoc, only run internal lints if the user is explicitly opting in
-        // or figure out a different way to avoid running lints for rustdoc.
-        if cx.tcx.sess.opts.actually_rustdoc {
-            return;
-        }
-
-        let (span, def_id, substs) = match expr.kind {
-            ExprKind::MethodCall(segment, _, _)
-                if let Some(def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) =>
-            {
-                (segment.ident.span, def_id, cx.typeck_results().node_substs(expr.hir_id))
-            },
-            _ => {
-                let &ty::FnDef(def_id, substs) =
-                    cx.typeck_results()
-                        .node_type(expr.hir_id)
-                        .kind() else { return };
-                (expr.span, def_id, substs)
-            }
-        };
+        let Some((span, def_id, substs)) = typeck_results_of_method_fn(cx, expr) else { return };
         if let Ok(Some(instance)) = ty::Instance::resolve(cx.tcx, cx.param_env, def_id, substs) {
             let def_id = instance.def_id();
             if cx.tcx.has_attr(def_id, sym::rustc_lint_query_instability) {
@@ -123,55 +132,115 @@
 ]);
 
 impl<'tcx> LateLintPass<'tcx> for TyTyKind {
-    fn check_path(&mut self, cx: &LateContext<'_>, path: &'tcx Path<'tcx>, _: HirId) {
-        let segments = path.segments.iter().rev().skip(1).rev();
-
-        if let Some(last) = segments.last() {
-            let span = path.span.with_hi(last.ident.span.hi());
-            if lint_ty_kind_usage(cx, last) {
-                cx.struct_span_lint(USAGE_OF_TY_TYKIND, span, |lint| {
-                    lint.build("usage of `ty::TyKind::<kind>`")
-                        .span_suggestion(
-                            span,
-                            "try using ty::<kind> directly",
-                            "ty".to_string(),
-                            Applicability::MaybeIncorrect, // ty maybe needs an import
-                        )
-                        .emit();
-                })
-            }
+    fn check_path(
+        &mut self,
+        cx: &LateContext<'tcx>,
+        path: &'tcx rustc_hir::Path<'tcx>,
+        _: rustc_hir::HirId,
+    ) {
+        if let Some(segment) = path.segments.iter().nth_back(1)
+        && let Some(res) = &segment.res
+        && lint_ty_kind_usage(cx, res)
+        {
+            let span = path.span.with_hi(
+                segment.args.map_or(segment.ident.span, |a| a.span_ext).hi()
+            );
+            cx.struct_span_lint(USAGE_OF_TY_TYKIND, path.span, |lint| {
+                lint.build("usage of `ty::TyKind::<kind>`")
+                    .span_suggestion(
+                        span,
+                        "try using `ty::<kind>` directly",
+                        "ty",
+                        Applicability::MaybeIncorrect, // ty maybe needs an import
+                    )
+                    .emit();
+            });
         }
     }
 
     fn check_ty(&mut self, cx: &LateContext<'_>, ty: &'tcx Ty<'tcx>) {
         match &ty.kind {
             TyKind::Path(QPath::Resolved(_, path)) => {
-                if let Some(last) = path.segments.iter().last() {
-                    if lint_ty_kind_usage(cx, last) {
-                        cx.struct_span_lint(USAGE_OF_TY_TYKIND, path.span, |lint| {
-                            lint.build("usage of `ty::TyKind`")
-                                .help("try using `Ty` instead")
-                                .emit();
-                        })
-                    } else {
-                        if ty.span.from_expansion() {
-                            return;
-                        }
-                        if let Some(t) = is_ty_or_ty_ctxt(cx, ty) {
-                            if path.segments.len() > 1 {
-                                cx.struct_span_lint(USAGE_OF_QUALIFIED_TY, path.span, |lint| {
-                                    lint.build(&format!("usage of qualified `ty::{}`", t))
+                if lint_ty_kind_usage(cx, &path.res) {
+                    cx.struct_span_lint(USAGE_OF_TY_TYKIND, path.span, |lint| {
+                        let hir = cx.tcx.hir();
+                        match hir.find(hir.get_parent_node(ty.hir_id)) {
+                            Some(Node::Pat(Pat {
+                                kind:
+                                    PatKind::Path(qpath)
+                                    | PatKind::TupleStruct(qpath, ..)
+                                    | PatKind::Struct(qpath, ..),
+                                ..
+                            })) => {
+                                if let QPath::TypeRelative(qpath_ty, ..) = qpath
+                                    && qpath_ty.hir_id == ty.hir_id
+                                {
+                                    lint.build("usage of `ty::TyKind::<kind>`")
                                         .span_suggestion(
                                             path.span,
-                                            "try importing it and using it unqualified",
-                                            t,
-                                            // The import probably needs to be changed
-                                            Applicability::MaybeIncorrect,
+                                            "try using `ty::<kind>` directly",
+                                            "ty",
+                                            Applicability::MaybeIncorrect, // ty maybe needs an import
                                         )
                                         .emit();
-                                })
+                                    return;
+                                }
                             }
+                            Some(Node::Expr(Expr {
+                                kind: ExprKind::Path(qpath),
+                                ..
+                            })) => {
+                                if let QPath::TypeRelative(qpath_ty, ..) = qpath
+                                    && qpath_ty.hir_id == ty.hir_id
+                                {
+                                    lint.build("usage of `ty::TyKind::<kind>`")
+                                        .span_suggestion(
+                                            path.span,
+                                            "try using `ty::<kind>` directly",
+                                            "ty",
+                                            Applicability::MaybeIncorrect, // ty maybe needs an import
+                                        )
+                                        .emit();
+                                    return;
+                                }
+                            }
+                            // Can't unify these two branches because qpath below is `&&` and above is `&`
+                            // and `A | B` paths don't play well together with adjustments, apparently.
+                            Some(Node::Expr(Expr {
+                                kind: ExprKind::Struct(qpath, ..),
+                                ..
+                            })) => {
+                                if let QPath::TypeRelative(qpath_ty, ..) = qpath
+                                    && qpath_ty.hir_id == ty.hir_id
+                                {
+                                    lint.build("usage of `ty::TyKind::<kind>`")
+                                        .span_suggestion(
+                                            path.span,
+                                            "try using `ty::<kind>` directly",
+                                            "ty",
+                                            Applicability::MaybeIncorrect, // ty maybe needs an import
+                                        )
+                                        .emit();
+                                    return;
+                                }
+                            }
+                            _ => {}
                         }
+                        lint.build("usage of `ty::TyKind`").help("try using `Ty` instead").emit();
+                    })
+                } else if !ty.span.from_expansion() && let Some(t) = is_ty_or_ty_ctxt(cx, &path) {
+                    if path.segments.len() > 1 {
+                        cx.struct_span_lint(USAGE_OF_QUALIFIED_TY, path.span, |lint| {
+                            lint.build(&format!("usage of qualified `ty::{}`", t))
+                                .span_suggestion(
+                                    path.span,
+                                    "try importing it and using it unqualified",
+                                    t,
+                                    // The import probably needs to be changed
+                                    Applicability::MaybeIncorrect,
+                                )
+                                .emit();
+                        })
                     }
                 }
             }
@@ -180,42 +249,37 @@
     }
 }
 
-fn lint_ty_kind_usage(cx: &LateContext<'_>, segment: &PathSegment<'_>) -> bool {
-    if let Some(res) = segment.res {
-        if let Some(did) = res.opt_def_id() {
-            return cx.tcx.is_diagnostic_item(sym::TyKind, did);
-        }
+fn lint_ty_kind_usage(cx: &LateContext<'_>, res: &Res) -> bool {
+    if let Some(did) = res.opt_def_id() {
+        cx.tcx.is_diagnostic_item(sym::TyKind, did) || cx.tcx.is_diagnostic_item(sym::IrTyKind, did)
+    } else {
+        false
     }
-
-    false
 }
 
-fn is_ty_or_ty_ctxt(cx: &LateContext<'_>, ty: &Ty<'_>) -> Option<String> {
-    if let TyKind::Path(QPath::Resolved(_, path)) = &ty.kind {
-        match path.res {
-            Res::Def(_, def_id) => {
-                if let Some(name @ (sym::Ty | sym::TyCtxt)) = cx.tcx.get_diagnostic_name(def_id) {
-                    return Some(format!("{}{}", name, gen_args(path.segments.last().unwrap())));
-                }
+fn is_ty_or_ty_ctxt(cx: &LateContext<'_>, path: &Path<'_>) -> Option<String> {
+    match &path.res {
+        Res::Def(_, def_id) => {
+            if let Some(name @ (sym::Ty | sym::TyCtxt)) = cx.tcx.get_diagnostic_name(*def_id) {
+                return Some(format!("{}{}", name, gen_args(path.segments.last().unwrap())));
             }
-            // Only lint on `&Ty` and `&TyCtxt` if it is used outside of a trait.
-            Res::SelfTy { trait_: None, alias_to: Some((did, _)) } => {
-                if let ty::Adt(adt, substs) = cx.tcx.type_of(did).kind() {
-                    if let Some(name @ (sym::Ty | sym::TyCtxt)) =
-                        cx.tcx.get_diagnostic_name(adt.did())
-                    {
-                        // NOTE: This path is currently unreachable as `Ty<'tcx>` is
-                        // defined as a type alias meaning that `impl<'tcx> Ty<'tcx>`
-                        // is not actually allowed.
-                        //
-                        // I(@lcnr) still kept this branch in so we don't miss this
-                        // if we ever change it in the future.
-                        return Some(format!("{}<{}>", name, substs[0]));
-                    }
-                }
-            }
-            _ => (),
         }
+        // Only lint on `&Ty` and `&TyCtxt` if it is used outside of a trait.
+        Res::SelfTy { trait_: None, alias_to: Some((did, _)) } => {
+            if let ty::Adt(adt, substs) = cx.tcx.type_of(did).kind() {
+                if let Some(name @ (sym::Ty | sym::TyCtxt)) = cx.tcx.get_diagnostic_name(adt.did())
+                {
+                    // NOTE: This path is currently unreachable as `Ty<'tcx>` is
+                    // defined as a type alias meaning that `impl<'tcx> Ty<'tcx>`
+                    // is not actually allowed.
+                    //
+                    // I(@lcnr) still kept this branch in so we don't miss this
+                    // if we ever change it in the future.
+                    return Some(format!("{}<{}>", name, substs[0]));
+                }
+            }
+        }
+        _ => (),
     }
 
     None
@@ -321,3 +385,70 @@
         }
     }
 }
+
+declare_tool_lint! {
+    pub rustc::UNTRANSLATABLE_DIAGNOSTIC,
+    Allow,
+    "prevent creation of diagnostics which cannot be translated",
+    report_in_external_macro: true
+}
+
+declare_tool_lint! {
+    pub rustc::DIAGNOSTIC_OUTSIDE_OF_IMPL,
+    Allow,
+    "prevent creation of diagnostics outside of `SessionDiagnostic`/`AddSubdiagnostic` impls",
+    report_in_external_macro: true
+}
+
+declare_lint_pass!(Diagnostics => [ UNTRANSLATABLE_DIAGNOSTIC, DIAGNOSTIC_OUTSIDE_OF_IMPL ]);
+
+impl LateLintPass<'_> for Diagnostics {
+    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
+        let Some((span, def_id, substs)) = typeck_results_of_method_fn(cx, expr) else { return };
+        debug!(?span, ?def_id, ?substs);
+        if let Ok(Some(instance)) = ty::Instance::resolve(cx.tcx, cx.param_env, def_id, substs) &&
+            !cx.tcx.has_attr(instance.def_id(), sym::rustc_lint_diagnostics)
+        {
+            return;
+        }
+
+        let mut found_impl = false;
+        for (_, parent) in cx.tcx.hir().parent_iter(expr.hir_id) {
+            debug!(?parent);
+            if let Node::Item(Item { kind: ItemKind::Impl(impl_), .. }) = parent &&
+                let Impl { of_trait: Some(of_trait), .. } = impl_ &&
+                let Some(def_id) = of_trait.trait_def_id() &&
+                let Some(name) = cx.tcx.get_diagnostic_name(def_id) &&
+                matches!(name, sym::SessionDiagnostic | sym::AddSubdiagnostic)
+            {
+                found_impl = true;
+                break;
+            }
+        }
+        debug!(?found_impl);
+        if !found_impl {
+            cx.struct_span_lint(DIAGNOSTIC_OUTSIDE_OF_IMPL, span, |lint| {
+                lint.build("diagnostics should only be created in `SessionDiagnostic`/`AddSubdiagnostic` impls")
+                    .emit();
+            })
+        }
+
+        let mut found_diagnostic_message = false;
+        for ty in substs.types() {
+            debug!(?ty);
+            if let Some(adt_def) = ty.ty_adt_def() &&
+                let Some(name) =  cx.tcx.get_diagnostic_name(adt_def.did()) &&
+                matches!(name, sym::DiagnosticMessage | sym::SubdiagnosticMessage)
+            {
+                found_diagnostic_message = true;
+                break;
+            }
+        }
+        debug!(?found_diagnostic_message);
+        if !found_diagnostic_message {
+            cx.struct_span_lint(UNTRANSLATABLE_DIAGNOSTIC, span, |lint| {
+                lint.build("diagnostics should be created using translatable messages").emit();
+            })
+        }
+    }
+}
diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs
index 0ce760b..c1d8d76 100644
--- a/compiler/rustc_lint/src/late.rs
+++ b/compiler/rustc_lint/src/late.rs
@@ -34,7 +34,7 @@
 
 /// Extract the `LintStore` from the query context.
 /// This function exists because we've erased `LintStore` as `dyn Any` in the context.
-crate fn unerased_lint_store(tcx: TyCtxt<'_>) -> &LintStore {
+pub(crate) fn unerased_lint_store(tcx: TyCtxt<'_>) -> &LintStore {
     let store: &dyn Any = &*tcx.lint_store;
     store.downcast_ref().unwrap()
 }
@@ -59,9 +59,11 @@
         let attrs = self.context.tcx.hir().attrs(id);
         let prev = self.context.last_node_with_lint_attrs;
         self.context.last_node_with_lint_attrs = id;
-        self.enter_attrs(attrs);
+        debug!("late context: enter_attrs({:?})", attrs);
+        lint_callback!(self, enter_lint_attrs, attrs);
         f(self);
-        self.exit_attrs(attrs);
+        debug!("late context: exit_attrs({:?})", attrs);
+        lint_callback!(self, exit_lint_attrs, attrs);
         self.context.last_node_with_lint_attrs = prev;
     }
 
@@ -81,16 +83,6 @@
         hir_visit::walk_mod(self, m, n);
         lint_callback!(self, check_mod_post, m, s, n);
     }
-
-    fn enter_attrs(&mut self, attrs: &'tcx [ast::Attribute]) {
-        debug!("late context: enter_attrs({:?})", attrs);
-        lint_callback!(self, enter_lint_attrs, attrs);
-    }
-
-    fn exit_attrs(&mut self, attrs: &'tcx [ast::Attribute]) {
-        debug!("late context: exit_attrs({:?})", attrs);
-        lint_callback!(self, exit_lint_attrs, attrs);
-    }
 }
 
 impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPass<'tcx, T> {
@@ -337,10 +329,8 @@
         hir_visit::walk_path(self, p);
     }
 
-    fn visit_attribute(&mut self, hir_id: hir::HirId, attr: &'tcx ast::Attribute) {
-        self.with_lint_attrs(hir_id, |cx| {
-            lint_callback!(cx, check_attribute, attr);
-        })
+    fn visit_attribute(&mut self, attr: &'tcx ast::Attribute) {
+        lint_callback!(self, check_attribute, attr);
     }
 }
 
@@ -402,7 +392,7 @@
     // Visit the crate attributes
     if hir_id == hir::CRATE_HIR_ID {
         for attr in tcx.hir().attrs(hir::CRATE_HIR_ID).iter() {
-            cx.visit_attribute(hir_id, attr)
+            cx.visit_attribute(attr)
         }
     }
 }
diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs
index 257549b..4773fed 100644
--- a/compiler/rustc_lint/src/levels.rs
+++ b/compiler/rustc_lint/src/levels.rs
@@ -14,7 +14,7 @@
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::{RegisteredTools, TyCtxt};
 use rustc_session::lint::{
-    builtin::{self, FORBIDDEN_LINT_GROUPS, UNFULFILLED_LINT_EXPECTATIONS},
+    builtin::{self, FORBIDDEN_LINT_GROUPS, SINGLE_USE_LIFETIMES, UNFULFILLED_LINT_EXPECTATIONS},
     Level, Lint, LintExpectationId, LintId,
 };
 use rustc_session::parse::{add_feature_diagnostics, feature_err};
@@ -117,7 +117,9 @@
             };
             for id in ids {
                 // ForceWarn and Forbid cannot be overridden
-                if let Some((Level::ForceWarn | Level::Forbid, _)) = self.current_specs().get(&id) {
+                if let Some((Level::ForceWarn(_) | Level::Forbid, _)) =
+                    self.current_specs().get(&id)
+                {
                     continue;
                 }
 
@@ -226,11 +228,18 @@
             return;
         }
 
-        if let Level::ForceWarn = old_level {
-            self.current_specs_mut().insert(id, (old_level, old_src));
-        } else {
-            self.current_specs_mut().insert(id, (level, src));
-        }
+        match (old_level, level) {
+            // If the new level is an expectation store it in `ForceWarn`
+            (Level::ForceWarn(_), Level::Expect(expectation_id)) => self
+                .current_specs_mut()
+                .insert(id, (Level::ForceWarn(Some(expectation_id)), old_src)),
+            // Keep `ForceWarn` level but drop the expectation
+            (Level::ForceWarn(_), _) => {
+                self.current_specs_mut().insert(id, (Level::ForceWarn(None), old_src))
+            }
+            // Set the lint level as normal
+            _ => self.current_specs_mut().insert(id, (level, src)),
+        };
     }
 
     /// Pushes a list of AST lint attributes onto this context.
@@ -259,8 +268,17 @@
         let sess = self.sess;
         let bad_attr = |span| struct_span_err!(sess, span, E0452, "malformed lint attribute input");
         for (attr_index, attr) in attrs.iter().enumerate() {
+            if attr.has_name(sym::automatically_derived) {
+                self.current_specs_mut().insert(
+                    LintId::of(SINGLE_USE_LIFETIMES),
+                    (Level::Allow, LintLevelSource::Default),
+                );
+                continue;
+            }
+
             let level = match Level::from_attr(attr) {
                 None => continue,
+                // This is the only lint level with a `LintExpectationId` that can be created from an attribute
                 Some(Level::Expect(unstable_id)) if let Some(hir_id) = source_hir_id => {
                     let stable_id = self.create_stable_id(unstable_id, hir_id, attr_index);
 
@@ -435,7 +453,7 @@
                                             .span_suggestion(
                                                 sp,
                                                 "change it to",
-                                                new_lint_name.to_string(),
+                                                new_lint_name,
                                                 Applicability::MachineApplicable,
                                             )
                                             .emit();
@@ -508,7 +526,7 @@
                                     err.span_suggestion(
                                         sp,
                                         "use the new name",
-                                        new_name.to_string(),
+                                        new_name,
                                         Applicability::MachineApplicable,
                                     );
                                 }
@@ -535,7 +553,7 @@
                                 db.span_suggestion(
                                     sp,
                                     "did you mean",
-                                    suggestion.to_string(),
+                                    suggestion,
                                     Applicability::MachineApplicable,
                                 );
                             }
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index 0a0f292..c1255ae 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -30,14 +30,12 @@
 #![feature(array_windows)]
 #![feature(box_patterns)]
 #![feature(control_flow_enum)]
-#![feature(crate_visibility_modifier)]
 #![feature(if_let_guard)]
 #![feature(iter_intersperse)]
 #![feature(iter_order_by)]
 #![feature(let_chains)]
 #![feature(let_else)]
 #![feature(never_type)]
-#![feature(nll)]
 #![recursion_limit = "256"]
 
 #[macro_use]
@@ -161,28 +159,16 @@
         $macro!(
             $args,
             [
-                // FIXME: Look into regression when this is used as a module lint
-                // May Depend on constants elsewhere
-                UnusedBrokenConst: UnusedBrokenConst,
-                // Needs to run after UnusedAttributes as it marks all `feature` attributes as used.
-                UnstableFeatures: UnstableFeatures,
                 // Tracks state across modules
                 UnnameableTestItems: UnnameableTestItems::new(),
                 // Tracks attributes of parents
                 MissingDoc: MissingDoc::new(),
-                // Depends on access levels
+                // Builds a global list of all impls of `Debug`.
                 // FIXME: Turn the computation of types which implement Debug into a query
                 // and change this to a module lint pass
                 MissingDebugImplementations: MissingDebugImplementations::default(),
-                ArrayIntoIter: ArrayIntoIter::default(),
+                // Keeps a global list of foreign declarations.
                 ClashingExternDeclarations: ClashingExternDeclarations::new(),
-                DropTraitConstraints: DropTraitConstraints,
-                TemporaryCStringAsPtr: TemporaryCStringAsPtr,
-                NonPanicFmt: NonPanicFmt,
-                NoopMethodCall: NoopMethodCall,
-                EnumIntrinsicsNonEnums: EnumIntrinsicsNonEnums,
-                InvalidAtomicOrdering: InvalidAtomicOrdering,
-                NamedAsmLabels: NamedAsmLabels,
             ]
         );
     };
@@ -218,6 +204,17 @@
                 ExplicitOutlivesRequirements: ExplicitOutlivesRequirements,
                 InvalidValue: InvalidValue,
                 DerefNullPtr: DerefNullPtr,
+                // May Depend on constants elsewhere
+                UnusedBrokenConst: UnusedBrokenConst,
+                UnstableFeatures: UnstableFeatures,
+                ArrayIntoIter: ArrayIntoIter::default(),
+                DropTraitConstraints: DropTraitConstraints,
+                TemporaryCStringAsPtr: TemporaryCStringAsPtr,
+                NonPanicFmt: NonPanicFmt,
+                NoopMethodCall: NoopMethodCall,
+                EnumIntrinsicsNonEnums: EnumIntrinsicsNonEnums,
+                InvalidAtomicOrdering: InvalidAtomicOrdering,
+                NamedAsmLabels: NamedAsmLabels,
             ]
         );
     };
@@ -510,6 +507,8 @@
     store.register_late_pass(|| Box::new(ExistingDocKeyword));
     store.register_lints(&TyTyKind::get_lints());
     store.register_late_pass(|| Box::new(TyTyKind));
+    store.register_lints(&Diagnostics::get_lints());
+    store.register_late_pass(|| Box::new(Diagnostics));
     store.register_lints(&PassByValue::get_lints());
     store.register_late_pass(|| Box::new(PassByValue));
     store.register_group(
diff --git a/compiler/rustc_lint/src/redundant_semicolon.rs b/compiler/rustc_lint/src/redundant_semicolon.rs
index 0fe6564..f06a8b8 100644
--- a/compiler/rustc_lint/src/redundant_semicolon.rs
+++ b/compiler/rustc_lint/src/redundant_semicolon.rs
@@ -54,9 +54,7 @@
             } else {
                 ("unnecessary trailing semicolon", "remove this semicolon")
             };
-            lint.build(msg)
-                .span_suggestion(span, rem, String::new(), Applicability::MaybeIncorrect)
-                .emit();
+            lint.build(msg).span_suggestion(span, rem, "", Applicability::MaybeIncorrect).emit();
         });
     }
 }
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index 62d427f..2a2dc68 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -8,7 +8,7 @@
 use rustc_hir::{is_range_literal, Expr, ExprKind, Node};
 use rustc_middle::ty::layout::{IntegerExt, LayoutOf, SizeSkeleton};
 use rustc_middle::ty::subst::SubstsRef;
-use rustc_middle::ty::{self, AdtKind, DefIdTree, Ty, TyCtxt, TypeFoldable};
+use rustc_middle::ty::{self, AdtKind, DefIdTree, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable};
 use rustc_span::source_map;
 use rustc_span::symbol::sym;
 use rustc_span::{Span, Symbol, DUMMY_SP};
@@ -651,7 +651,7 @@
 declare_lint_pass!(ImproperCTypesDefinitions => [IMPROPER_CTYPES_DEFINITIONS]);
 
 #[derive(Clone, Copy)]
-crate enum CItemKind {
+pub(crate) enum CItemKind {
     Declaration,
     Definition,
 }
@@ -667,7 +667,10 @@
     FfiUnsafe { ty: Ty<'tcx>, reason: String, help: Option<String> },
 }
 
-crate fn nonnull_optimization_guaranteed<'tcx>(tcx: TyCtxt<'tcx>, def: ty::AdtDef<'tcx>) -> bool {
+pub(crate) fn nonnull_optimization_guaranteed<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    def: ty::AdtDef<'tcx>,
+) -> bool {
     tcx.has_attr(def.did(), sym::rustc_nonnull_optimization_guaranteed)
 }
 
@@ -766,7 +769,7 @@
 /// Currently restricted to function pointers, boxes, references, `core::num::NonZero*`,
 /// `core::ptr::NonNull`, and `#[repr(transparent)]` newtypes.
 /// FIXME: This duplicates code in codegen.
-crate fn repr_nullable_ptr<'tcx>(
+pub(crate) fn repr_nullable_ptr<'tcx>(
     cx: &LateContext<'tcx>,
     ty: Ty<'tcx>,
     ckind: CItemKind,
diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs
index 8cae95f..73f353e 100644
--- a/compiler/rustc_lint/src/unused.rs
+++ b/compiler/rustc_lint/src/unused.rs
@@ -160,7 +160,7 @@
                 lint.span_suggestion_verbose(
                     expr.span.shrink_to_lo(),
                     "use `let _ = ...` to ignore the resulting value",
-                    "let _ = ".to_string(),
+                    "let _ = ",
                     Applicability::MachineApplicable,
                 );
                 lint.emit();
diff --git a/compiler/rustc_lint_defs/Cargo.toml b/compiler/rustc_lint_defs/Cargo.toml
index fcd8c37..2bf34d8 100644
--- a/compiler/rustc_lint_defs/Cargo.toml
+++ b/compiler/rustc_lint_defs/Cargo.toml
@@ -4,6 +4,7 @@
 edition = "2021"
 
 [dependencies]
+serde = { version = "1.0.125", features = ["derive"] }
 rustc_ast = { path = "../rustc_ast" }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_error_messages = { path = "../rustc_error_messages" }
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index f942970..b1bfd61 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -474,7 +474,7 @@
 }
 
 declare_lint! {
-    /// The `unknown_lints` lint detects unrecognized lint attribute.
+    /// The `unknown_lints` lint detects unrecognized lint attributes.
     ///
     /// ### Example
     ///
@@ -1154,7 +1154,6 @@
     /// ### Example
     ///
     /// ```compile_fail
-    /// #![deny(unaligned_references)]
     /// #[repr(packed)]
     /// pub struct Foo {
     ///     field1: u64,
@@ -2614,7 +2613,7 @@
     ///
     /// ### Example
     ///
-    /// ```rust
+    /// ```compile_fail
     /// # #![allow(unused)]
     /// enum E {
     ///     A,
@@ -2650,10 +2649,11 @@
     /// [issue #73333]: https://github.com/rust-lang/rust/issues/73333
     /// [`Copy`]: https://doc.rust-lang.org/std/marker/trait.Copy.html
     pub CENUM_IMPL_DROP_CAST,
-    Warn,
+    Deny,
     "a C-like enum implementing Drop is cast",
     @future_incompatible = FutureIncompatibleInfo {
         reference: "issue #73333 <https://github.com/rust-lang/rust/issues/73333>",
+        reason: FutureIncompatibilityReason::FutureReleaseErrorReportNow,
     };
 }
 
diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs
index 57b4f96..1cd19c7 100644
--- a/compiler/rustc_lint_defs/src/lib.rs
+++ b/compiler/rustc_lint_defs/src/lib.rs
@@ -14,6 +14,8 @@
 use rustc_span::{sym, symbol::Ident, Span, Symbol};
 use rustc_target::spec::abi::Abi;
 
+use serde::{Deserialize, Serialize};
+
 pub mod builtin;
 
 #[macro_export]
@@ -24,6 +26,9 @@
     ("is", $x:expr) => {
         if $x == 1 { "is" } else { "are" }
     };
+    ("was", $x:expr) => {
+        if $x == 1 { "was" } else { "were" }
+    };
     ("this", $x:expr) => {
         if $x == 1 { "this" } else { "these" }
     };
@@ -34,7 +39,7 @@
 /// All suggestions are marked with an `Applicability`. Tools use the applicability of a suggestion
 /// to determine whether it should be automatically applied or if the user should be consulted
 /// before applying the suggestion.
-#[derive(Copy, Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
+#[derive(Copy, Clone, Debug, PartialEq, Hash, Encodable, Decodable, Serialize, Deserialize)]
 pub enum Applicability {
     /// The suggestion is definitely what the user intended, or maintains the exact meaning of the code.
     /// This suggestion should be automatically applied.
@@ -160,13 +165,19 @@
     ///
     /// See RFC 2383.
     ///
-    /// The `LintExpectationId` is used to later link a lint emission to the actual
+    /// The [`LintExpectationId`] is used to later link a lint emission to the actual
     /// expectation. It can be ignored in most cases.
     Expect(LintExpectationId),
     /// The `warn` level will produce a warning if the lint was violated, however the
     /// compiler will continue with its execution.
     Warn,
-    ForceWarn,
+    /// This lint level is a special case of [`Warn`], that can't be overridden. This is used
+    /// to ensure that a lint can't be suppressed. This lint level can currently only be set
+    /// via the console and is therefore session specific.
+    ///
+    /// The [`LintExpectationId`] is intended to fulfill expectations marked via the
+    /// `#[expect]` attribute, that will still be suppressed due to the level.
+    ForceWarn(Option<LintExpectationId>),
     /// The `deny` level will produce an error and stop further execution after the lint
     /// pass is complete.
     Deny,
@@ -182,7 +193,7 @@
             Level::Allow => "allow",
             Level::Expect(_) => "expect",
             Level::Warn => "warn",
-            Level::ForceWarn => "force-warn",
+            Level::ForceWarn(_) => "force-warn",
             Level::Deny => "deny",
             Level::Forbid => "forbid",
         }
@@ -217,7 +228,7 @@
 
     pub fn is_error(self) -> bool {
         match self {
-            Level::Allow | Level::Expect(_) | Level::Warn | Level::ForceWarn => false,
+            Level::Allow | Level::Expect(_) | Level::Warn | Level::ForceWarn(_) => false,
             Level::Deny | Level::Forbid => true,
         }
     }
@@ -423,7 +434,11 @@
     DeprecatedMacro(Option<Symbol>, Span),
     MissingAbi(Span, Abi),
     UnusedDocComment(Span),
-    UnusedBuiltinAttribute { attr_name: Symbol, macro_name: String, invoc_span: Span },
+    UnusedBuiltinAttribute {
+        attr_name: Symbol,
+        macro_name: String,
+        invoc_span: Span,
+    },
     PatternsInFnsWithoutBody(Span, Ident),
     LegacyDeriveHelpers(Span),
     ProcMacroBackCompat(String),
@@ -435,6 +450,16 @@
     UnicodeTextFlow(Span, String),
     UnexpectedCfg((Symbol, Span), Option<(Symbol, Span)>),
     DeprecatedWhereclauseLocation(Span, String),
+    SingleUseLifetime {
+        /// Span of the parameter which declares this lifetime.
+        param_span: Span,
+        /// Span of the code that should be removed when eliding this lifetime.
+        /// This span should include leading or trailing comma.
+        deletion_span: Span,
+        /// Span of the single use, or None if the lifetime is never used.
+        /// If true, the lifetime will be fully elided.
+        use_span: Option<(Span, bool)>,
+    },
 }
 
 /// Lints that are buffered up early on in the `Session` before the
diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
index 6d79e66..a52d534 100644
--- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
@@ -672,10 +672,20 @@
   unwrap(M)->addModuleFlag(MergeBehavior, Name, Value);
 }
 
+extern "C" bool LLVMRustHasModuleFlag(LLVMModuleRef M, const char *Name,
+                                      size_t Len) {
+  return unwrap(M)->getModuleFlag(StringRef(Name, Len)) != nullptr;
+}
+
 extern "C" LLVMValueRef LLVMRustMetadataAsValue(LLVMContextRef C, LLVMMetadataRef MD) {
   return wrap(MetadataAsValue::get(*unwrap(C), unwrap(MD)));
 }
 
+extern "C" void LLVMRustGlobalAddMetadata(
+    LLVMValueRef Global, unsigned Kind, LLVMMetadataRef MD) {
+  unwrap<GlobalObject>(Global)->addMetadata(Kind, *unwrap<MDNode>(MD));
+}
+
 extern "C" LLVMRustDIBuilderRef LLVMRustDIBuilderCreate(LLVMModuleRef M) {
   return new DIBuilder(*unwrap(M));
 }
@@ -1542,11 +1552,19 @@
     auto C = unwrap<llvm::ConstantInt>(CV);
     if (C->getBitWidth() > 128) { return false; }
     APInt AP;
+#if LLVM_VERSION_GE(15, 0)
+    if (sext) {
+        AP = C->getValue().sext(128);
+    } else {
+        AP = C->getValue().zext(128);
+    }
+#else
     if (sext) {
         AP = C->getValue().sextOrSelf(128);
     } else {
         AP = C->getValue().zextOrSelf(128);
     }
+#endif
     *low = AP.getLoBits(64).getZExtValue();
     *high = AP.getHiBits(64).getZExtValue();
     return true;
diff --git a/compiler/rustc_llvm/src/lib.rs b/compiler/rustc_llvm/src/lib.rs
index b63f81b..8eade02 100644
--- a/compiler/rustc_llvm/src/lib.rs
+++ b/compiler/rustc_llvm/src/lib.rs
@@ -1,4 +1,3 @@
-#![feature(nll)]
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 
 // NOTE: This crate only exists to allow linking on mingw targets.
diff --git a/compiler/rustc_log/src/lib.rs b/compiler/rustc_log/src/lib.rs
index c152815..f2ec80b 100644
--- a/compiler/rustc_log/src/lib.rs
+++ b/compiler/rustc_log/src/lib.rs
@@ -69,13 +69,7 @@
 
     let verbose_entry_exit = match env::var_os(String::from(env) + "_ENTRY_EXIT") {
         None => false,
-        Some(v) => {
-            if &v == "0" {
-                false
-            } else {
-                true
-            }
-        }
+        Some(v) => &v != "0",
     };
 
     let layer = tracing_tree::HierarchicalLayer::default()
diff --git a/compiler/rustc_macros/Cargo.toml b/compiler/rustc_macros/Cargo.toml
index a9192be..25b3aad 100644
--- a/compiler/rustc_macros/Cargo.toml
+++ b/compiler/rustc_macros/Cargo.toml
@@ -7,7 +7,11 @@
 proc-macro = true
 
 [dependencies]
+annotate-snippets = "0.8.0"
+fluent-bundle = "0.15.2"
+fluent-syntax = "0.11"
 synstructure = "0.12.1"
 syn = { version = "1", features = ["full"] }
 proc-macro2 = "1"
 quote = "1"
+unic-langid = { version = "0.9.0", features = ["macros"] }
diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic.rs b/compiler/rustc_macros/src/diagnostics/diagnostic.rs
index dac3e98..95ee0d4 100644
--- a/compiler/rustc_macros/src/diagnostics/diagnostic.rs
+++ b/compiler/rustc_macros/src/diagnostics/diagnostic.rs
@@ -13,7 +13,7 @@
 use std::collections::HashMap;
 use std::str::FromStr;
 use syn::{spanned::Spanned, Attribute, Meta, MetaList, MetaNameValue, Type};
-use synstructure::Structure;
+use synstructure::{BindingInfo, Structure};
 
 /// The central struct for constructing the `into_diagnostic` method from an annotated struct.
 pub(crate) struct SessionDiagnosticDerive<'a> {
@@ -71,55 +71,42 @@
                     }
                 };
 
+                // Keep track of which fields are subdiagnostics or have no attributes.
+                let mut subdiagnostics_or_empty = std::collections::HashSet::new();
+
                 // Generates calls to `span_label` and similar functions based on the attributes
                 // on fields. Code for suggestions uses formatting machinery and the value of
                 // other fields - because any given field can be referenced multiple times, it
-                // should be accessed through a borrow. When passing fields to `set_arg` (which
-                // happens below) for Fluent, we want to move the data, so that has to happen
-                // in a separate pass over the fields.
-                let attrs = structure.each(|field_binding| {
-                    let field = field_binding.ast();
-                    let result = field.attrs.iter().map(|attr| {
-                        builder
-                            .generate_field_attr_code(
-                                attr,
-                                FieldInfo {
-                                    vis: &field.vis,
-                                    binding: field_binding,
-                                    ty: &field.ty,
-                                    span: &field.span(),
-                                },
-                            )
-                            .unwrap_or_else(|v| v.to_compile_error())
-                    });
+                // should be accessed through a borrow. When passing fields to `add_subdiagnostic`
+                // or `set_arg` (which happens below) for Fluent, we want to move the data, so that
+                // has to happen in a separate pass over the fields.
+                let attrs = structure
+                    .clone()
+                    .filter(|field_binding| {
+                        let attrs = &field_binding.ast().attrs;
 
-                    quote! { #(#result);* }
-                });
+                        (!attrs.is_empty()
+                            && attrs.iter().all(|attr| {
+                                "subdiagnostic"
+                                    != attr.path.segments.last().unwrap().ident.to_string()
+                            }))
+                            || {
+                                subdiagnostics_or_empty.insert(field_binding.binding.clone());
+                                false
+                            }
+                    })
+                    .each(|field_binding| builder.generate_field_attrs_code(field_binding));
 
-                // When generating `set_arg` calls, move data rather than borrow it to avoid
-                // requiring clones - this must therefore be the last use of each field (for
-                // example, any formatting machinery that might refer to a field should be
-                // generated already).
                 structure.bind_with(|_| synstructure::BindStyle::Move);
-                let args = structure.each(|field_binding| {
-                    let field = field_binding.ast();
-                    // When a field has attributes like `#[label]` or `#[note]` then it doesn't
-                    // need to be passed as an argument to the diagnostic. But when a field has no
-                    // attributes then it must be passed as an argument to the diagnostic so that
-                    // it can be referred to by Fluent messages.
-                    if field.attrs.is_empty() {
-                        let diag = &builder.diag;
-                        let ident = field_binding.ast().ident.as_ref().unwrap();
-                        quote! {
-                            #diag.set_arg(
-                                stringify!(#ident),
-                                #field_binding
-                            );
-                        }
-                    } else {
-                        quote! {}
-                    }
-                });
+                // When a field has attributes like `#[label]` or `#[note]` then it doesn't
+                // need to be passed as an argument to the diagnostic. But when a field has no
+                // attributes or a `#[subdiagnostic]` attribute then it must be passed as an
+                // argument to the diagnostic so that it can be referred to by Fluent messages.
+                let args = structure
+                    .filter(|field_binding| {
+                        subdiagnostics_or_empty.contains(&field_binding.binding)
+                    })
+                    .each(|field_binding| builder.generate_field_attrs_code(field_binding));
 
                 let span = ast.span().unwrap();
                 let (diag, sess) = (&builder.diag, &builder.sess);
@@ -139,14 +126,14 @@
                     (Some((SessionDiagnosticKind::Error, _)), Some((slug, _))) => {
                         quote! {
                             let mut #diag = #sess.struct_err(
-                                rustc_errors::DiagnosticMessage::fluent(#slug),
+                                rustc_errors::DiagnosticMessage::new(#slug),
                             );
                         }
                     }
                     (Some((SessionDiagnosticKind::Warn, _)), Some((slug, _))) => {
                         quote! {
                             let mut #diag = #sess.struct_warn(
-                                rustc_errors::DiagnosticMessage::fluent(#slug),
+                                rustc_errors::DiagnosticMessage::new(#slug),
                             );
                         }
                     }
@@ -267,21 +254,6 @@
 
         if matches!(name, "help" | "note") && matches!(meta, Meta::Path(_) | Meta::NameValue(_)) {
             let diag = &self.diag;
-            let slug = match &self.slug {
-                Some((slug, _)) => slug.as_str(),
-                None => throw_span_err!(
-                    span,
-                    &format!(
-                        "`#[{}{}]` must come after `#[error(..)]` or `#[warn(..)]`",
-                        name,
-                        match meta {
-                            Meta::Path(_) => "",
-                            Meta::NameValue(_) => " = ...",
-                            _ => unreachable!(),
-                        }
-                    )
-                ),
-            };
             let id = match meta {
                 Meta::Path(..) => quote! { #name },
                 Meta::NameValue(MetaNameValue { lit: syn::Lit::Str(s), .. }) => {
@@ -292,7 +264,7 @@
             let fn_name = proc_macro2::Ident::new(name, attr.span());
 
             return Ok(quote! {
-                #diag.#fn_name(rustc_errors::DiagnosticMessage::fluent_attr(#slug, #id));
+                #diag.#fn_name(rustc_errors::SubdiagnosticMessage::attr(#id));
             });
         }
 
@@ -347,36 +319,60 @@
         Ok(tokens.drain(..).collect())
     }
 
-    fn generate_field_attr_code(
-        &mut self,
-        attr: &syn::Attribute,
-        info: FieldInfo<'_>,
-    ) -> Result<TokenStream, SessionDiagnosticDeriveError> {
-        let field_binding = &info.binding.binding;
+    fn generate_field_attrs_code(&mut self, binding_info: &BindingInfo<'_>) -> TokenStream {
+        let field = binding_info.ast();
+        let field_binding = &binding_info.binding;
 
-        let inner_ty = FieldInnerTy::from_type(&info.ty);
-        let name = attr.path.segments.last().unwrap().ident.to_string();
-        let (binding, needs_destructure) = match (name.as_str(), &inner_ty) {
-            // `primary_span` can accept a `Vec<Span>` so don't destructure that.
-            ("primary_span", FieldInnerTy::Vec(_)) => (quote! { #field_binding.clone() }, false),
-            _ => (quote! { *#field_binding }, true),
-        };
+        let inner_ty = FieldInnerTy::from_type(&field.ty);
 
-        let generated_code = self.generate_inner_field_code(
-            attr,
-            FieldInfo {
-                vis: info.vis,
-                binding: info.binding,
-                ty: inner_ty.inner_type().unwrap_or(&info.ty),
-                span: info.span,
-            },
-            binding,
-        )?;
-
-        if needs_destructure {
-            Ok(inner_ty.with(field_binding, generated_code))
+        // When generating `set_arg` or `add_subdiagnostic` calls, move data rather than
+        // borrow it to avoid requiring clones - this must therefore be the last use of
+        // each field (for example, any formatting machinery that might refer to a field
+        // should be generated already).
+        if field.attrs.is_empty() {
+            let diag = &self.diag;
+            let ident = field.ident.as_ref().unwrap();
+            quote! {
+                #diag.set_arg(
+                    stringify!(#ident),
+                    #field_binding
+                );
+            }
         } else {
-            Ok(generated_code)
+            field
+                .attrs
+                .iter()
+                .map(move |attr| {
+                    let name = attr.path.segments.last().unwrap().ident.to_string();
+                    let (binding, needs_destructure) = match (name.as_str(), &inner_ty) {
+                        // `primary_span` can accept a `Vec<Span>` so don't destructure that.
+                        ("primary_span", FieldInnerTy::Vec(_)) => {
+                            (quote! { #field_binding.clone() }, false)
+                        }
+                        // `subdiagnostics` are not derefed because they are bound by value.
+                        ("subdiagnostic", _) => (quote! { #field_binding }, true),
+                        _ => (quote! { *#field_binding }, true),
+                    };
+
+                    let generated_code = self
+                        .generate_inner_field_code(
+                            attr,
+                            FieldInfo {
+                                binding: binding_info,
+                                ty: inner_ty.inner_type().unwrap_or(&field.ty),
+                                span: &field.span(),
+                            },
+                            binding,
+                        )
+                        .unwrap_or_else(|v| v.to_compile_error());
+
+                    if needs_destructure {
+                        inner_ty.with(field_binding, generated_code)
+                    } else {
+                        generated_code
+                    }
+                })
+                .collect()
         }
     }
 
@@ -514,13 +510,8 @@
 
                 let method = format_ident!("span_{}", name);
 
-                let slug = self
-                    .slug
-                    .as_ref()
-                    .map(|(slug, _)| slug.as_str())
-                    .unwrap_or_else(|| "missing-slug");
                 let msg = msg.as_deref().unwrap_or("suggestion");
-                let msg = quote! { rustc_errors::DiagnosticMessage::fluent_attr(#slug, #msg) };
+                let msg = quote! { rustc_errors::SubdiagnosticMessage::attr(#msg) };
                 let code = code.unwrap_or_else(|| quote! { String::new() });
 
                 Ok(quote! { #diag.#method(#span_field, #msg, #code, #applicability); })
@@ -538,14 +529,11 @@
         fluent_attr_identifier: &str,
     ) -> TokenStream {
         let diag = &self.diag;
-
-        let slug =
-            self.slug.as_ref().map(|(slug, _)| slug.as_str()).unwrap_or_else(|| "missing-slug");
         let fn_name = format_ident!("span_{}", kind);
         quote! {
             #diag.#fn_name(
                 #field_binding,
-                rustc_errors::DiagnosticMessage::fluent_attr(#slug, #fluent_attr_identifier)
+                rustc_errors::SubdiagnosticMessage::attr(#fluent_attr_identifier)
             );
         }
     }
@@ -554,9 +542,8 @@
     /// and `fluent_attr_identifier`.
     fn add_subdiagnostic(&self, kind: &Ident, fluent_attr_identifier: &str) -> TokenStream {
         let diag = &self.diag;
-        let slug = self.slug.as_ref().map(|(slug, _)| slug.as_str()).unwrap_or("missing-slug");
         quote! {
-            #diag.#kind(rustc_errors::DiagnosticMessage::fluent_attr(#slug, #fluent_attr_identifier));
+            #diag.#kind(rustc_errors::SubdiagnosticMessage::attr(#fluent_attr_identifier));
         }
     }
 
diff --git a/compiler/rustc_macros/src/diagnostics/fluent.rs b/compiler/rustc_macros/src/diagnostics/fluent.rs
new file mode 100644
index 0000000..42a9bf4
--- /dev/null
+++ b/compiler/rustc_macros/src/diagnostics/fluent.rs
@@ -0,0 +1,260 @@
+use annotate_snippets::{
+    display_list::DisplayList,
+    snippet::{Annotation, AnnotationType, Slice, Snippet, SourceAnnotation},
+};
+use fluent_bundle::{FluentBundle, FluentError, FluentResource};
+use fluent_syntax::{
+    ast::{Attribute, Entry, Identifier, Message},
+    parser::ParserError,
+};
+use proc_macro::{Diagnostic, Level, Span};
+use proc_macro2::TokenStream;
+use quote::quote;
+use std::{
+    collections::{HashMap, HashSet},
+    fs::File,
+    io::Read,
+    path::{Path, PathBuf},
+};
+use syn::{
+    parse::{Parse, ParseStream},
+    parse_macro_input,
+    punctuated::Punctuated,
+    token, Ident, LitStr, Result,
+};
+use unic_langid::langid;
+
+struct Resource {
+    ident: Ident,
+    #[allow(dead_code)]
+    fat_arrow_token: token::FatArrow,
+    resource: LitStr,
+}
+
+impl Parse for Resource {
+    fn parse(input: ParseStream<'_>) -> Result<Self> {
+        Ok(Resource {
+            ident: input.parse()?,
+            fat_arrow_token: input.parse()?,
+            resource: input.parse()?,
+        })
+    }
+}
+
+struct Resources(Punctuated<Resource, token::Comma>);
+
+impl Parse for Resources {
+    fn parse(input: ParseStream<'_>) -> Result<Self> {
+        let mut resources = Punctuated::new();
+        loop {
+            if input.is_empty() || input.peek(token::Brace) {
+                break;
+            }
+            let value = input.parse()?;
+            resources.push_value(value);
+            if !input.peek(token::Comma) {
+                break;
+            }
+            let punct = input.parse()?;
+            resources.push_punct(punct);
+        }
+        Ok(Resources(resources))
+    }
+}
+
+/// Helper function for returning an absolute path for macro-invocation relative file paths.
+///
+/// If the input is already absolute, then the input is returned. If the input is not absolute,
+/// then it is appended to the directory containing the source file with this macro invocation.
+fn invocation_relative_path_to_absolute(span: Span, path: &str) -> PathBuf {
+    let path = Path::new(path);
+    if path.is_absolute() {
+        path.to_path_buf()
+    } else {
+        // `/a/b/c/foo/bar.rs` contains the current macro invocation
+        let mut source_file_path = span.source_file().path();
+        // `/a/b/c/foo/`
+        source_file_path.pop();
+        // `/a/b/c/foo/../locales/en-US/example.ftl`
+        source_file_path.push(path);
+        source_file_path
+    }
+}
+
+/// See [rustc_macros::fluent_messages].
+pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
+    let resources = parse_macro_input!(input as Resources);
+
+    // Cannot iterate over individual messages in a bundle, so do that using the
+    // `FluentResource` instead. Construct a bundle anyway to find out if there are conflicting
+    // messages in the resources.
+    let mut bundle = FluentBundle::new(vec![langid!("en-US")]);
+
+    // Map of Fluent identifiers to the `Span` of the resource that defined them, used for better
+    // diagnostics.
+    let mut previous_defns = HashMap::new();
+
+    let mut includes = TokenStream::new();
+    let mut generated = TokenStream::new();
+    for res in resources.0 {
+        let ident_span = res.ident.span().unwrap();
+        let path_span = res.resource.span().unwrap();
+
+        // Set of Fluent attribute names already output, to avoid duplicate type errors - any given
+        // constant created for a given attribute is the same.
+        let mut previous_attrs = HashSet::new();
+
+        let relative_ftl_path = res.resource.value();
+        let absolute_ftl_path =
+            invocation_relative_path_to_absolute(ident_span, &relative_ftl_path);
+        // As this macro also outputs an `include_str!` for this file, the macro will always be
+        // re-executed when the file changes.
+        let mut resource_file = match File::open(absolute_ftl_path) {
+            Ok(resource_file) => resource_file,
+            Err(e) => {
+                Diagnostic::spanned(path_span, Level::Error, "could not open Fluent resource")
+                    .note(e.to_string())
+                    .emit();
+                continue;
+            }
+        };
+        let mut resource_contents = String::new();
+        if let Err(e) = resource_file.read_to_string(&mut resource_contents) {
+            Diagnostic::spanned(path_span, Level::Error, "could not read Fluent resource")
+                .note(e.to_string())
+                .emit();
+            continue;
+        }
+        let resource = match FluentResource::try_new(resource_contents) {
+            Ok(resource) => resource,
+            Err((this, errs)) => {
+                Diagnostic::spanned(path_span, Level::Error, "could not parse Fluent resource")
+                    .help("see additional errors emitted")
+                    .emit();
+                for ParserError { pos, slice: _, kind } in errs {
+                    let mut err = kind.to_string();
+                    // Entirely unnecessary string modification so that the error message starts
+                    // with a lowercase as rustc errors do.
+                    err.replace_range(
+                        0..1,
+                        &err.chars().next().unwrap().to_lowercase().to_string(),
+                    );
+
+                    let line_starts: Vec<usize> = std::iter::once(0)
+                        .chain(
+                            this.source()
+                                .char_indices()
+                                .filter_map(|(i, c)| Some(i + 1).filter(|_| c == '\n')),
+                        )
+                        .collect();
+                    let line_start = line_starts
+                        .iter()
+                        .enumerate()
+                        .map(|(line, idx)| (line + 1, idx))
+                        .filter(|(_, idx)| **idx <= pos.start)
+                        .last()
+                        .unwrap()
+                        .0;
+
+                    let snippet = Snippet {
+                        title: Some(Annotation {
+                            label: Some(&err),
+                            id: None,
+                            annotation_type: AnnotationType::Error,
+                        }),
+                        footer: vec![],
+                        slices: vec![Slice {
+                            source: this.source(),
+                            line_start,
+                            origin: Some(&relative_ftl_path),
+                            fold: true,
+                            annotations: vec![SourceAnnotation {
+                                label: "",
+                                annotation_type: AnnotationType::Error,
+                                range: (pos.start, pos.end - 1),
+                            }],
+                        }],
+                        opt: Default::default(),
+                    };
+                    let dl = DisplayList::from(snippet);
+                    eprintln!("{}\n", dl);
+                }
+                continue;
+            }
+        };
+
+        let mut constants = TokenStream::new();
+        for entry in resource.entries() {
+            let span = res.ident.span();
+            if let Entry::Message(Message { id: Identifier { name }, attributes, .. }) = entry {
+                let _ = previous_defns.entry(name.to_string()).or_insert(ident_span);
+
+                // `typeck-foo-bar` => `foo_bar`
+                let snake_name = Ident::new(
+                    &name.replace(&format!("{}-", res.ident), "").replace("-", "_"),
+                    span,
+                );
+                constants.extend(quote! {
+                    pub const #snake_name: crate::DiagnosticMessage =
+                        crate::DiagnosticMessage::FluentIdentifier(
+                            std::borrow::Cow::Borrowed(#name),
+                            None
+                        );
+                });
+
+                for Attribute { id: Identifier { name: attr_name }, .. } in attributes {
+                    let snake_name = Ident::new(&attr_name.replace("-", "_"), span);
+                    if !previous_attrs.insert(snake_name.clone()) {
+                        continue;
+                    }
+
+                    constants.extend(quote! {
+                        pub const #snake_name: crate::SubdiagnosticMessage =
+                            crate::SubdiagnosticMessage::FluentAttr(
+                                std::borrow::Cow::Borrowed(#attr_name)
+                            );
+                    });
+                }
+            }
+        }
+
+        if let Err(errs) = bundle.add_resource(resource) {
+            for e in errs {
+                match e {
+                    FluentError::Overriding { kind, id } => {
+                        Diagnostic::spanned(
+                            ident_span,
+                            Level::Error,
+                            format!("overrides existing {}: `{}`", kind, id),
+                        )
+                        .span_help(previous_defns[&id], "previously defined in this resource")
+                        .emit();
+                    }
+                    FluentError::ResolverError(_) | FluentError::ParserError(_) => unreachable!(),
+                }
+            }
+        }
+
+        includes.extend(quote! { include_str!(#relative_ftl_path), });
+
+        let ident = res.ident;
+        generated.extend(quote! {
+            pub mod #ident {
+                #constants
+            }
+        });
+    }
+
+    quote! {
+        #[allow(non_upper_case_globals)]
+        #[doc(hidden)]
+        pub mod fluent_generated {
+            pub static DEFAULT_LOCALE_RESOURCES: &'static [&'static str] = &[
+                #includes
+            ];
+
+            #generated
+        }
+    }
+    .into()
+}
diff --git a/compiler/rustc_macros/src/diagnostics/mod.rs b/compiler/rustc_macros/src/diagnostics/mod.rs
index 73ad415..69573d9 100644
--- a/compiler/rustc_macros/src/diagnostics/mod.rs
+++ b/compiler/rustc_macros/src/diagnostics/mod.rs
@@ -1,9 +1,11 @@
 mod diagnostic;
 mod error;
+mod fluent;
 mod subdiagnostic;
 mod utils;
 
 use diagnostic::SessionDiagnosticDerive;
+pub(crate) use fluent::fluent_messages;
 use proc_macro2::TokenStream;
 use quote::format_ident;
 use subdiagnostic::SessionSubdiagnosticDerive;
@@ -12,7 +14,7 @@
 /// Implements `#[derive(SessionDiagnostic)]`, which allows for errors to be specified as a struct,
 /// independent from the actual diagnostics emitting code.
 ///
-/// ```ignore (pseudo-rust)
+/// ```ignore (rust)
 /// # extern crate rustc_errors;
 /// # use rustc_errors::Applicability;
 /// # extern crate rustc_span;
@@ -43,7 +45,7 @@
 ///
 /// Then, later, to emit the error:
 ///
-/// ```ignore (pseudo-rust)
+/// ```ignore (rust)
 /// sess.emit_err(MoveOutOfBorrowError {
 ///     expected,
 ///     actual,
@@ -67,7 +69,7 @@
 /// suggestions to be specified as a structs or enums, independent from the actual diagnostics
 /// emitting code or diagnostic derives.
 ///
-/// ```ignore (pseudo-rust)
+/// ```ignore (rust)
 /// #[derive(SessionSubdiagnostic)]
 /// pub enum ExpectedIdentifierLabel<'tcx> {
 ///     #[label(slug = "parser-expected-identifier")]
@@ -104,7 +106,7 @@
 ///
 /// Then, later, to add the subdiagnostic:
 ///
-/// ```ignore (pseudo-rust)
+/// ```ignore (rust)
 /// diag.subdiagnostic(ExpectedIdentifierLabel::WithoutFound { span });
 ///
 /// diag.subdiagnostic(RawIdentifierSuggestion { span, applicability, ident });
diff --git a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs
index ae5b9db..9aeb484 100644
--- a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs
+++ b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs
@@ -303,7 +303,6 @@
 
         let inner_ty = FieldInnerTy::from_type(&ast.ty);
         let info = FieldInfo {
-            vis: &ast.vis,
             binding: binding,
             ty: inner_ty.inner_type().unwrap_or(&ast.ty),
             span: &ast.span(),
@@ -398,7 +397,7 @@
 
         let diag = &self.diag;
         let name = format_ident!("{}{}", if span_field.is_some() { "span_" } else { "" }, kind);
-        let message = quote! { rustc_errors::DiagnosticMessage::fluent(#slug) };
+        let message = quote! { rustc_errors::SubdiagnosticMessage::message(#slug) };
         let call = if matches!(kind, SubdiagnosticKind::Suggestion(..)) {
             if let Some(span) = span_field {
                 quote! { #diag.#name(#span, #message, #code, #applicability); }
diff --git a/compiler/rustc_macros/src/diagnostics/utils.rs b/compiler/rustc_macros/src/diagnostics/utils.rs
index af5a308..636bcf1 100644
--- a/compiler/rustc_macros/src/diagnostics/utils.rs
+++ b/compiler/rustc_macros/src/diagnostics/utils.rs
@@ -4,7 +4,7 @@
 use quote::{format_ident, quote, ToTokens};
 use std::collections::BTreeSet;
 use std::str::FromStr;
-use syn::{spanned::Spanned, Attribute, Meta, Type, TypeTuple, Visibility};
+use syn::{spanned::Spanned, Attribute, Meta, Type, TypeTuple};
 use synstructure::BindingInfo;
 
 /// Checks whether the type name of `ty` matches `name`.
@@ -158,7 +158,6 @@
 /// Field information passed to the builder. Deliberately omits attrs to discourage the
 /// `generate_*` methods from walking the attributes themselves.
 pub(crate) struct FieldInfo<'a> {
-    pub(crate) vis: &'a Visibility,
     pub(crate) binding: &'a BindingInfo<'a>,
     pub(crate) ty: &'a Type,
     pub(crate) span: &'a proc_macro2::Span,
diff --git a/compiler/rustc_macros/src/lib.rs b/compiler/rustc_macros/src/lib.rs
index 0baebdb..7c8e3c6 100644
--- a/compiler/rustc_macros/src/lib.rs
+++ b/compiler/rustc_macros/src/lib.rs
@@ -2,6 +2,7 @@
 #![feature(let_else)]
 #![feature(never_type)]
 #![feature(proc_macro_diagnostic)]
+#![feature(proc_macro_span)]
 #![allow(rustc::default_hash_types)]
 #![recursion_limit = "128"]
 
@@ -49,6 +50,64 @@
     newtype::newtype(input)
 }
 
+/// Implements the `fluent_messages` macro, which performs compile-time validation of the
+/// compiler's Fluent resources (i.e. that the resources parse and don't multiply define the same
+/// messages) and generates constants that make using those messages in diagnostics more ergonomic.
+///
+/// For example, given the following invocation of the macro..
+///
+/// ```ignore (rust)
+/// fluent_messages! {
+///     typeck => "./typeck.ftl",
+/// }
+/// ```
+/// ..where `typeck.ftl` has the following contents..
+///
+/// ```fluent
+/// typeck-field-multiply-specified-in-initializer =
+///     field `{$ident}` specified more than once
+///     .label = used more than once
+///     .label-previous-use = first use of `{$ident}`
+/// ```
+/// ...then the macro parse the Fluent resource, emitting a diagnostic if it fails to do so, and
+/// will generate the following code:
+///
+/// ```ignore (rust)
+/// pub static DEFAULT_LOCALE_RESOURCES: &'static [&'static str] = &[
+///     include_str!("./typeck.ftl"),
+/// ];
+///
+/// mod fluent_generated {
+///     mod typeck {
+///         pub const field_multiply_specified_in_initializer: DiagnosticMessage =
+///             DiagnosticMessage::fluent("typeck-field-multiply-specified-in-initializer");
+///         pub const field_multiply_specified_in_initializer_label_previous_use: DiagnosticMessage =
+///             DiagnosticMessage::fluent_attr(
+///                 "typeck-field-multiply-specified-in-initializer",
+///                 "previous-use-label"
+///             );
+///     }
+/// }
+/// ```
+/// When emitting a diagnostic, the generated constants can be used as follows:
+///
+/// ```ignore (rust)
+/// let mut err = sess.struct_span_err(
+///     span,
+///     fluent::typeck::field_multiply_specified_in_initializer
+/// );
+/// err.span_default_label(span);
+/// err.span_label(
+///     previous_use_span,
+///     fluent::typeck::field_multiply_specified_in_initializer_label_previous_use
+/// );
+/// err.emit();
+/// ```
+#[proc_macro]
+pub fn fluent_messages(input: TokenStream) -> TokenStream {
+    diagnostics::fluent_messages(input)
+}
+
 decl_derive!([HashStable, attributes(stable_hasher)] => hash_stable::hash_stable_derive);
 decl_derive!(
     [HashStable_Generic, attributes(stable_hasher)] =>
diff --git a/compiler/rustc_macros/src/newtype.rs b/compiler/rustc_macros/src/newtype.rs
index c8b31cd..0a77b73 100644
--- a/compiler/rustc_macros/src/newtype.rs
+++ b/compiler/rustc_macros/src/newtype.rs
@@ -137,8 +137,8 @@
                     }
                 }
                 impl<E: ::rustc_serialize::Encoder> ::rustc_serialize::Encodable<E> for #name {
-                    fn encode(&self, e: &mut E) -> Result<(), E::Error> {
-                        e.emit_u32(self.private)
+                    fn encode(&self, e: &mut E) {
+                        e.emit_u32(self.private);
                     }
                 }
             }
diff --git a/compiler/rustc_macros/src/serialize.rs b/compiler/rustc_macros/src/serialize.rs
index 535158f..82e6972 100644
--- a/compiler/rustc_macros/src/serialize.rs
+++ b/compiler/rustc_macros/src/serialize.rs
@@ -8,7 +8,7 @@
     if !s.ast().generics.lifetimes().any(|lt| lt.lifetime.ident == "tcx") {
         s.add_impl_generic(parse_quote! { 'tcx });
     }
-    s.add_impl_generic(parse_quote! {#decoder_ty: ::rustc_middle::ty::codec::TyDecoder<'tcx>});
+    s.add_impl_generic(parse_quote! {#decoder_ty: ::rustc_type_ir::codec::TyDecoder<I = ::rustc_middle::ty::TyCtxt<'tcx>>});
     s.add_bounds(synstructure::AddBounds::Generics);
 
     decodable_body(s, decoder_ty)
@@ -95,7 +95,7 @@
         s.add_impl_generic(parse_quote! {'tcx});
     }
     let encoder_ty = quote! { __E };
-    s.add_impl_generic(parse_quote! {#encoder_ty: ::rustc_middle::ty::codec::TyEncoder<'tcx>});
+    s.add_impl_generic(parse_quote! {#encoder_ty: ::rustc_type_ir::codec::TyEncoder<I = ::rustc_middle::ty::TyCtxt<'tcx>>});
     s.add_bounds(synstructure::AddBounds::Generics);
 
     encodable_body(s, encoder_ty, false)
@@ -140,87 +140,55 @@
 
     let encode_body = match s.variants() {
         [_] => {
-            let mut field_idx = 0usize;
             let encode_inner = s.each_variant(|vi| {
                 vi.bindings()
                     .iter()
                     .map(|binding| {
                         let bind_ident = &binding.binding;
-                        let field_name = binding
-                            .ast()
-                            .ident
-                            .as_ref()
-                            .map_or_else(|| field_idx.to_string(), |i| i.to_string());
-                        let first = field_idx == 0;
                         let result = quote! {
-                            match ::rustc_serialize::Encoder::emit_struct_field(
+                            ::rustc_serialize::Encodable::<#encoder_ty>::encode(
+                                #bind_ident,
                                 __encoder,
-                                #field_name,
-                                #first,
-                                |__encoder|
-                                ::rustc_serialize::Encodable::<#encoder_ty>::encode(#bind_ident, __encoder),
-                            ) {
-                                ::std::result::Result::Ok(()) => (),
-                                ::std::result::Result::Err(__err)
-                                    => return ::std::result::Result::Err(__err),
-                            }
+                            );
                         };
-                        field_idx += 1;
                         result
                     })
                     .collect::<TokenStream>()
             });
-            let no_fields = field_idx == 0;
             quote! {
-                ::rustc_serialize::Encoder::emit_struct(__encoder, #no_fields, |__encoder| {
-                    ::std::result::Result::Ok(match *self { #encode_inner })
-                })
+                match *self { #encode_inner }
             }
         }
         _ => {
             let mut variant_idx = 0usize;
             let encode_inner = s.each_variant(|vi| {
-                let variant_name = vi.ast().ident.to_string();
-                let mut field_idx = 0usize;
-
                 let encode_fields: TokenStream = vi
                     .bindings()
                     .iter()
                     .map(|binding| {
                         let bind_ident = &binding.binding;
-                        let first = field_idx == 0;
                         let result = quote! {
-                            match ::rustc_serialize::Encoder::emit_enum_variant_arg(
+                            ::rustc_serialize::Encodable::<#encoder_ty>::encode(
+                                #bind_ident,
                                 __encoder,
-                                #first,
-                                |__encoder|
-                                ::rustc_serialize::Encodable::<#encoder_ty>::encode(#bind_ident, __encoder),
-                            ) {
-                                ::std::result::Result::Ok(()) => (),
-                                ::std::result::Result::Err(__err)
-                                    => return ::std::result::Result::Err(__err),
-                            }
+                            );
                         };
-                        field_idx += 1;
                         result
                     })
                     .collect();
 
-                let result = if field_idx != 0 {
+                let result = if !vi.bindings().is_empty() {
                     quote! {
                         ::rustc_serialize::Encoder::emit_enum_variant(
                             __encoder,
-                            #variant_name,
                             #variant_idx,
-                            #field_idx,
-                            |__encoder| { ::std::result::Result::Ok({ #encode_fields }) }
+                            |__encoder| { #encode_fields }
                         )
                     }
                 } else {
                     quote! {
                         ::rustc_serialize::Encoder::emit_fieldless_enum_variant::<#variant_idx>(
                             __encoder,
-                            #variant_name,
                         )
                     }
                 };
@@ -228,11 +196,9 @@
                 result
             });
             quote! {
-                ::rustc_serialize::Encoder::emit_enum(__encoder, |__encoder| {
-                    match *self {
-                        #encode_inner
-                    }
-                })
+                match *self {
+                    #encode_inner
+                }
             }
         }
     };
@@ -249,7 +215,7 @@
             fn encode(
                 &self,
                 __encoder: &mut #encoder_ty,
-            ) -> ::std::result::Result<(), <#encoder_ty as ::rustc_serialize::Encoder>::Error> {
+            ) {
                 #lints
                 #encode_body
             }
diff --git a/compiler/rustc_macros/src/type_foldable.rs b/compiler/rustc_macros/src/type_foldable.rs
index bc8213a..9e834d3 100644
--- a/compiler/rustc_macros/src/type_foldable.rs
+++ b/compiler/rustc_macros/src/type_foldable.rs
@@ -30,14 +30,14 @@
     s.bound_impl(
         quote!(::rustc_middle::ty::fold::TypeFoldable<'tcx>),
         quote! {
-            fn try_super_fold_with<__F: ::rustc_middle::ty::fold::FallibleTypeFolder<'tcx>>(
+            fn try_fold_with<__F: ::rustc_middle::ty::fold::FallibleTypeFolder<'tcx>>(
                 self,
                 __folder: &mut __F
             ) -> Result<Self, __F::Error> {
                 Ok(match self { #body_fold })
             }
 
-            fn super_visit_with<__F: ::rustc_middle::ty::fold::TypeVisitor<'tcx>>(
+            fn visit_with<__F: ::rustc_middle::ty::fold::TypeVisitor<'tcx>>(
                 &self,
                 __folder: &mut __F
             ) -> ::std::ops::ControlFlow<__F::BreakTy> {
diff --git a/compiler/rustc_metadata/Cargo.toml b/compiler/rustc_metadata/Cargo.toml
index 59796dd..41224e3 100644
--- a/compiler/rustc_metadata/Cargo.toml
+++ b/compiler/rustc_metadata/Cargo.toml
@@ -27,3 +27,4 @@
 rustc_expand = { path = "../rustc_expand" }
 rustc_span = { path = "../rustc_span" }
 rustc_session = { path = "../rustc_session" }
+rustc_type_ir = { path = "../rustc_type_ir" }
diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs
index 3c545e6..555db58 100644
--- a/compiler/rustc_metadata/src/creader.rs
+++ b/compiler/rustc_metadata/src/creader.rs
@@ -70,7 +70,7 @@
     ProcMacro(SyntaxExtension),
 }
 
-crate struct Library {
+pub(crate) struct Library {
     pub source: CrateSource,
     pub metadata: MetadataBlob,
 }
@@ -82,7 +82,7 @@
 
 /// A reference to `CrateMetadata` that can also give access to whole crate store when necessary.
 #[derive(Clone, Copy)]
-crate struct CrateMetadataRef<'a> {
+pub(crate) struct CrateMetadataRef<'a> {
     pub cdata: &'a CrateMetadata,
     pub cstore: &'a CStore,
 }
@@ -133,7 +133,11 @@
         CrateNum::new(self.metas.len() - 1)
     }
 
-    crate fn get_crate_data(&self, cnum: CrateNum) -> CrateMetadataRef<'_> {
+    pub fn has_crate_data(&self, cnum: CrateNum) -> bool {
+        self.metas[cnum].is_some()
+    }
+
+    pub(crate) fn get_crate_data(&self, cnum: CrateNum) -> CrateMetadataRef<'_> {
         let cdata = self.metas[cnum]
             .as_ref()
             .unwrap_or_else(|| panic!("Failed to get crate data for {:?}", cnum));
@@ -145,7 +149,7 @@
         self.metas[cnum] = Some(Lrc::new(data));
     }
 
-    crate fn iter_crate_data(&self) -> impl Iterator<Item = (CrateNum, &CrateMetadata)> {
+    pub(crate) fn iter_crate_data(&self) -> impl Iterator<Item = (CrateNum, &CrateMetadata)> {
         self.metas
             .iter_enumerated()
             .filter_map(|(cnum, data)| data.as_ref().map(|data| (cnum, &**data)))
@@ -164,7 +168,7 @@
         }
     }
 
-    crate fn crate_dependencies_in_postorder(&self, cnum: CrateNum) -> Vec<CrateNum> {
+    pub(crate) fn crate_dependencies_in_postorder(&self, cnum: CrateNum) -> Vec<CrateNum> {
         let mut deps = Vec::new();
         if cnum == LOCAL_CRATE {
             for (cnum, _) in self.iter_crate_data() {
@@ -182,15 +186,15 @@
         deps
     }
 
-    crate fn injected_panic_runtime(&self) -> Option<CrateNum> {
+    pub(crate) fn injected_panic_runtime(&self) -> Option<CrateNum> {
         self.injected_panic_runtime
     }
 
-    crate fn allocator_kind(&self) -> Option<AllocatorKind> {
+    pub(crate) fn allocator_kind(&self) -> Option<AllocatorKind> {
         self.allocator_kind
     }
 
-    crate fn has_global_allocator(&self) -> bool {
+    pub(crate) fn has_global_allocator(&self) -> bool {
         self.has_global_allocator
     }
 
@@ -323,7 +327,7 @@
         None
     }
 
-    fn verify_no_symbol_conflicts(&self, root: &CrateRoot<'_>) -> Result<(), CrateError> {
+    fn verify_no_symbol_conflicts(&self, root: &CrateRoot) -> Result<(), CrateError> {
         // Check for (potential) conflicts with the local crate
         if self.sess.local_stable_crate_id() == root.stable_crate_id() {
             return Err(CrateError::SymbolConflictsCurrent(root.name()));
@@ -342,7 +346,7 @@
 
     fn verify_no_stable_crate_id_hash_conflicts(
         &mut self,
-        root: &CrateRoot<'_>,
+        root: &CrateRoot,
         cnum: CrateNum,
     ) -> Result<(), CrateError> {
         if let Some(existing) = self.cstore.stable_crate_ids.insert(root.stable_crate_id(), cnum) {
@@ -623,7 +627,7 @@
     fn resolve_crate_deps(
         &mut self,
         root: &CratePaths,
-        crate_root: &CrateRoot<'_>,
+        crate_root: &CrateRoot,
         metadata: &MetadataBlob,
         krate: CrateNum,
         dep_kind: CrateDepKind,
diff --git a/compiler/rustc_metadata/src/dependency_format.rs b/compiler/rustc_metadata/src/dependency_format.rs
index ddc3e10..245b207 100644
--- a/compiler/rustc_metadata/src/dependency_format.rs
+++ b/compiler/rustc_metadata/src/dependency_format.rs
@@ -62,7 +62,7 @@
 use rustc_session::cstore::LinkagePreference::{self, RequireDynamic, RequireStatic};
 use rustc_target::spec::PanicStrategy;
 
-crate fn calculate(tcx: TyCtxt<'_>) -> Dependencies {
+pub(crate) fn calculate(tcx: TyCtxt<'_>) -> Dependencies {
     tcx.sess
         .crate_types()
         .iter()
diff --git a/compiler/rustc_metadata/src/foreign_modules.rs b/compiler/rustc_metadata/src/foreign_modules.rs
index 70da961..2ca4cd1 100644
--- a/compiler/rustc_metadata/src/foreign_modules.rs
+++ b/compiler/rustc_metadata/src/foreign_modules.rs
@@ -3,7 +3,7 @@
 use rustc_middle::ty::TyCtxt;
 use rustc_session::cstore::ForeignModule;
 
-crate fn collect(tcx: TyCtxt<'_>) -> Vec<ForeignModule> {
+pub(crate) fn collect(tcx: TyCtxt<'_>) -> Vec<ForeignModule> {
     let mut modules = Vec::new();
     for id in tcx.hir().items() {
         if !matches!(tcx.def_kind(id.def_id), DefKind::ForeignMod) {
diff --git a/compiler/rustc_metadata/src/lib.rs b/compiler/rustc_metadata/src/lib.rs
index dfed9dd..5ad1639 100644
--- a/compiler/rustc_metadata/src/lib.rs
+++ b/compiler/rustc_metadata/src/lib.rs
@@ -1,14 +1,17 @@
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
-#![feature(crate_visibility_modifier)]
+#![feature(decl_macro)]
 #![feature(drain_filter)]
 #![feature(generators)]
+#![feature(generic_associated_types)]
+#![feature(iter_from_generator)]
+#![feature(let_chains)]
 #![feature(let_else)]
-#![feature(nll)]
 #![feature(once_cell)]
 #![feature(proc_macro_internals)]
 #![feature(macro_metavar_expr)]
 #![feature(min_specialization)]
 #![feature(slice_as_chunks)]
+#![feature(trusted_len)]
 #![feature(try_blocks)]
 #![feature(never_type)]
 #![recursion_limit = "256"]
diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs
index 43bda7c..dbe5322 100644
--- a/compiler/rustc_metadata/src/locator.rs
+++ b/compiler/rustc_metadata/src/locator.rs
@@ -239,7 +239,7 @@
 use tracing::{debug, info};
 
 #[derive(Clone)]
-crate struct CrateLocator<'a> {
+pub(crate) struct CrateLocator<'a> {
     // Immutable per-session configuration.
     only_needs_metadata: bool,
     sysroot: &'a Path,
@@ -260,19 +260,19 @@
 }
 
 #[derive(Clone)]
-crate struct CratePaths {
+pub(crate) struct CratePaths {
     name: Symbol,
     source: CrateSource,
 }
 
 impl CratePaths {
-    crate fn new(name: Symbol, source: CrateSource) -> CratePaths {
+    pub(crate) fn new(name: Symbol, source: CrateSource) -> CratePaths {
         CratePaths { name, source }
     }
 }
 
 #[derive(Copy, Clone, PartialEq)]
-crate enum CrateFlavor {
+pub(crate) enum CrateFlavor {
     Rlib,
     Rmeta,
     Dylib,
@@ -289,7 +289,7 @@
 }
 
 impl<'a> CrateLocator<'a> {
-    crate fn new(
+    pub(crate) fn new(
         sess: &'a Session,
         metadata_loader: &'a dyn MetadataLoader,
         crate_name: Symbol,
@@ -344,7 +344,7 @@
         }
     }
 
-    crate fn reset(&mut self) {
+    pub(crate) fn reset(&mut self) {
         self.crate_rejections.via_hash.clear();
         self.crate_rejections.via_triple.clear();
         self.crate_rejections.via_kind.clear();
@@ -353,7 +353,7 @@
         self.crate_rejections.via_invalid.clear();
     }
 
-    crate fn maybe_load_library_crate(&mut self) -> Result<Option<Library>, CrateError> {
+    pub(crate) fn maybe_load_library_crate(&mut self) -> Result<Option<Library>, CrateError> {
         if !self.exact_paths.is_empty() {
             return self.find_commandline_library();
         }
@@ -728,7 +728,7 @@
         Ok(self.extract_lib(rlibs, rmetas, dylibs)?.map(|(_, lib)| lib))
     }
 
-    crate fn into_error(self, root: Option<CratePaths>) -> CrateError {
+    pub(crate) fn into_error(self, root: Option<CratePaths>) -> CrateError {
         CrateError::LocatorCombined(CombinedLocatorError {
             crate_name: self.crate_name,
             root,
@@ -894,7 +894,7 @@
 /// Candidate rejection reasons collected during crate search.
 /// If no candidate is accepted, then these reasons are presented to the user,
 /// otherwise they are ignored.
-crate struct CombinedLocatorError {
+pub(crate) struct CombinedLocatorError {
     crate_name: Symbol,
     root: Option<CratePaths>,
     triple: TargetTriple,
@@ -903,7 +903,7 @@
     crate_rejections: CrateRejections,
 }
 
-crate enum CrateError {
+pub(crate) enum CrateError {
     NonAsciiName(Symbol),
     ExternLocationNotExist(Symbol, PathBuf),
     ExternLocationNotFile(Symbol, PathBuf),
@@ -937,7 +937,7 @@
 }
 
 impl CrateError {
-    crate fn report(self, sess: &Session, span: Span, missing_core: bool) {
+    pub(crate) fn report(self, sess: &Session, span: Span, missing_core: bool) {
         let mut diag = match self {
             CrateError::NonAsciiName(crate_name) => sess.struct_span_err(
                 span,
diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs
index eec66fb..c33219e 100644
--- a/compiler/rustc_metadata/src/native_libs.rs
+++ b/compiler/rustc_metadata/src/native_libs.rs
@@ -1,4 +1,4 @@
-use rustc_ast::CRATE_NODE_ID;
+use rustc_ast::{NestedMetaItem, CRATE_NODE_ID};
 use rustc_attr as attr;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::struct_span_err;
@@ -9,11 +9,10 @@
 use rustc_session::parse::feature_err;
 use rustc_session::utils::NativeLibKind;
 use rustc_session::Session;
-use rustc_span::symbol::{kw, sym, Symbol};
-use rustc_span::Span;
+use rustc_span::symbol::{sym, Symbol};
 use rustc_target::spec::abi::Abi;
 
-crate fn collect(tcx: TyCtxt<'_>) -> Vec<NativeLib> {
+pub(crate) fn collect(tcx: TyCtxt<'_>) -> Vec<NativeLib> {
     let mut collector = Collector { tcx, libs: Vec::new() };
     for id in tcx.hir().items() {
         collector.process_item(id);
@@ -22,7 +21,7 @@
     collector.libs
 }
 
-crate fn relevant_lib(sess: &Session, lib: &NativeLib) -> bool {
+pub(crate) fn relevant_lib(sess: &Session, lib: &NativeLib) -> bool {
     match lib.cfg {
         Some(ref cfg) => attr::cfg_matches(cfg, &sess.parse_sess, CRATE_NODE_ID, None),
         None => true,
@@ -51,283 +50,296 @@
 
         // Process all of the #[link(..)]-style arguments
         let sess = &self.tcx.sess;
+        let features = self.tcx.features();
         for m in self.tcx.hir().attrs(it.hir_id()).iter().filter(|a| a.has_name(sym::link)) {
             let Some(items) = m.meta_item_list() else {
                 continue;
             };
-            let mut lib = NativeLib {
-                name: None,
-                kind: NativeLibKind::Unspecified,
-                cfg: None,
-                foreign_module: Some(it.def_id.to_def_id()),
-                wasm_import_module: None,
-                verbatim: None,
-                dll_imports: Vec::new(),
-            };
-            let mut kind_specified = false;
 
+            let mut name = None;
+            let mut kind = None;
+            let mut modifiers = None;
+            let mut cfg = None;
+            let mut wasm_import_module = None;
             for item in items.iter() {
-                if item.has_name(sym::kind) {
-                    kind_specified = true;
-                    let Some(kind) = item.value_str() else {
-                        continue; // skip like historical compilers
-                    };
-                    lib.kind = match kind.as_str() {
-                        "static" => NativeLibKind::Static { bundle: None, whole_archive: None },
-                        "static-nobundle" => {
-                            sess.struct_span_warn(
-                                item.span(),
-                                "library kind `static-nobundle` has been superseded by specifying \
-                                modifier `-bundle` with library kind `static`",
-                            )
-                            .emit();
-                            if !self.tcx.features().static_nobundle {
-                                feature_err(
-                                    &self.tcx.sess.parse_sess,
-                                    sym::static_nobundle,
-                                    item.span(),
-                                    "kind=\"static-nobundle\" is unstable",
-                                )
-                                .emit();
-                            }
-                            NativeLibKind::Static { bundle: Some(false), whole_archive: None }
-                        }
-                        "dylib" => NativeLibKind::Dylib { as_needed: None },
-                        "framework" => NativeLibKind::Framework { as_needed: None },
-                        "raw-dylib" => NativeLibKind::RawDylib,
-                        k => {
-                            struct_span_err!(sess, item.span(), E0458, "unknown kind: `{}`", k)
-                                .span_label(item.span(), "unknown kind")
-                                .span_label(m.span, "")
-                                .emit();
-                            NativeLibKind::Unspecified
-                        }
-                    };
-                } else if item.has_name(sym::name) {
-                    lib.name = item.value_str();
-                } else if item.has_name(sym::cfg) {
-                    let Some(cfg) = item.meta_item_list() else {
-                        continue; // skip like historical compilers
-                    };
-                    if cfg.is_empty() {
-                        sess.span_err(item.span(), "`cfg()` must have an argument");
-                    } else if let cfg @ Some(..) = cfg[0].meta_item() {
-                        lib.cfg = cfg.cloned();
-                    } else {
-                        sess.span_err(cfg[0].span(), "invalid argument for `cfg(..)`");
-                    }
-                } else if item.has_name(sym::wasm_import_module) {
-                    match item.value_str() {
-                        Some(s) => lib.wasm_import_module = Some(s),
-                        None => {
-                            let msg = "must be of the form `#[link(wasm_import_module = \"...\")]`";
+                match item.name_or_empty() {
+                    sym::name => {
+                        if name.is_some() {
+                            let msg = "multiple `name` arguments in a single `#[link]` attribute";
                             sess.span_err(item.span(), msg);
+                            continue;
                         }
+                        let Some(link_name) = item.value_str() else {
+                            let msg = "link name must be of the form `name = \"string\"`";
+                            sess.span_err(item.span(), msg);
+                            continue;
+                        };
+                        let span = item.name_value_literal_span().unwrap();
+                        if link_name.is_empty() {
+                            struct_span_err!(sess, span, E0454, "link name must not be empty")
+                                .span_label(span, "empty link name")
+                                .emit();
+                        }
+                        name = Some((link_name, span));
                     }
-                } else {
-                    // currently, like past compilers, ignore unknown
-                    // directives here.
-                }
-            }
+                    sym::kind => {
+                        if kind.is_some() {
+                            let msg = "multiple `kind` arguments in a single `#[link]` attribute";
+                            sess.span_err(item.span(), msg);
+                            continue;
+                        }
+                        let Some(link_kind) = item.value_str() else {
+                            let msg = "link kind must be of the form `kind = \"string\"`";
+                            sess.span_err(item.span(), msg);
+                            continue;
+                        };
 
-            // Do this outside the above loop so we don't depend on modifiers coming
-            // after kinds
-            let mut modifiers_count = 0;
-            for item in items.iter().filter(|item| item.has_name(sym::modifiers)) {
-                if let Some(modifiers) = item.value_str() {
-                    modifiers_count += 1;
-                    let span = item.name_value_literal_span().unwrap();
-                    let mut has_duplicate_modifiers = false;
-                    for modifier in modifiers.as_str().split(',') {
-                        let (modifier, value) = match modifier.strip_prefix(&['+', '-']) {
-                            Some(m) => (m, modifier.starts_with('+')),
-                            None => {
-                                // Note: this error also excludes the case with empty modifier
-                                // string, like `modifiers = ""`.
-                                sess.span_err(
-                                    span,
-                                    "invalid linking modifier syntax, expected '+' or '-' prefix \
-                                    before one of: bundle, verbatim, whole-archive, as-needed",
+                        let span = item.name_value_literal_span().unwrap();
+                        let link_kind = match link_kind.as_str() {
+                            "static" => NativeLibKind::Static { bundle: None, whole_archive: None },
+                            "dylib" => NativeLibKind::Dylib { as_needed: None },
+                            "framework" => {
+                                if !sess.target.is_like_osx {
+                                    struct_span_err!(
+                                        sess,
+                                        span,
+                                        E0455,
+                                        "link kind `framework` is only supported on Apple targets"
+                                    )
+                                    .emit();
+                                }
+                                NativeLibKind::Framework { as_needed: None }
+                            }
+                            "raw-dylib" => {
+                                if !sess.target.is_like_windows {
+                                    struct_span_err!(
+                                        sess,
+                                        span,
+                                        E0455,
+                                        "link kind `raw-dylib` is only supported on Windows targets"
+                                    )
+                                    .emit();
+                                } else if !features.raw_dylib {
+                                    feature_err(
+                                        &sess.parse_sess,
+                                        sym::raw_dylib,
+                                        span,
+                                        "link kind `raw-dylib` is unstable",
+                                    )
+                                    .emit();
+                                }
+                                NativeLibKind::RawDylib
+                            }
+                            kind => {
+                                let msg = format!(
+                                    "unknown link kind `{kind}`, expected one of: \
+                                     static, dylib, framework, raw-dylib"
                                 );
+                                struct_span_err!(sess, span, E0458, "{}", msg)
+                                    .span_label(span, "unknown link kind")
+                                    .emit();
                                 continue;
                             }
                         };
-
-                        match (modifier, &mut lib.kind) {
-                            ("bundle", NativeLibKind::Static { bundle, .. }) => {
-                                if bundle.is_some() {
-                                    has_duplicate_modifiers = true;
-                                }
-                                *bundle = Some(value);
-                            }
-                            ("bundle", _) => {
-                                sess.span_err(
-                                    span,
-                                    "bundle linking modifier is only compatible with \
-                                `static` linking kind",
-                                );
-                            }
-
-                            ("verbatim", _) => {
-                                if lib.verbatim.is_some() {
-                                    has_duplicate_modifiers = true;
-                                }
-                                lib.verbatim = Some(value);
-                            }
-
-                            ("whole-archive", NativeLibKind::Static { whole_archive, .. }) => {
-                                if whole_archive.is_some() {
-                                    has_duplicate_modifiers = true;
-                                }
-                                *whole_archive = Some(value);
-                            }
-                            ("whole-archive", _) => {
-                                sess.span_err(
-                                    span,
-                                    "whole-archive linking modifier is only compatible with \
-                                `static` linking kind",
-                                );
-                            }
-
-                            ("as-needed", NativeLibKind::Dylib { as_needed })
-                            | ("as-needed", NativeLibKind::Framework { as_needed }) => {
-                                if as_needed.is_some() {
-                                    has_duplicate_modifiers = true;
-                                }
-                                *as_needed = Some(value);
-                            }
-                            ("as-needed", _) => {
-                                sess.span_err(
-                                    span,
-                                    "as-needed linking modifier is only compatible with \
-                                `dylib` and `framework` linking kinds",
-                                );
-                            }
-
-                            _ => {
-                                sess.span_err(
-                                    span,
-                                    &format!(
-                                        "unrecognized linking modifier `{}`, expected one \
-                                    of: bundle, verbatim, whole-archive, as-needed",
-                                        modifier
-                                    ),
-                                );
-                            }
-                        }
+                        kind = Some(link_kind);
                     }
-                    if has_duplicate_modifiers {
-                        let msg =
-                            "same modifier is used multiple times in a single `modifiers` argument";
+                    sym::modifiers => {
+                        if modifiers.is_some() {
+                            let msg =
+                                "multiple `modifiers` arguments in a single `#[link]` attribute";
+                            sess.span_err(item.span(), msg);
+                            continue;
+                        }
+                        let Some(link_modifiers) = item.value_str() else {
+                            let msg = "link modifiers must be of the form `modifiers = \"string\"`";
+                            sess.span_err(item.span(), msg);
+                            continue;
+                        };
+                        modifiers = Some((link_modifiers, item.name_value_literal_span().unwrap()));
+                    }
+                    sym::cfg => {
+                        if cfg.is_some() {
+                            let msg = "multiple `cfg` arguments in a single `#[link]` attribute";
+                            sess.span_err(item.span(), msg);
+                            continue;
+                        }
+                        let Some(link_cfg) = item.meta_item_list() else {
+                            let msg = "link cfg must be of the form `cfg(/* predicate */)`";
+                            sess.span_err(item.span(), msg);
+                            continue;
+                        };
+                        let [NestedMetaItem::MetaItem(link_cfg)] = link_cfg else {
+                            let msg = "link cfg must have a single predicate argument";
+                            sess.span_err(item.span(), msg);
+                            continue;
+                        };
+                        if !features.link_cfg {
+                            feature_err(
+                                &sess.parse_sess,
+                                sym::link_cfg,
+                                item.span(),
+                                "link cfg is unstable",
+                            )
+                            .emit();
+                        }
+                        cfg = Some(link_cfg.clone());
+                    }
+                    sym::wasm_import_module => {
+                        if wasm_import_module.is_some() {
+                            let msg = "multiple `wasm_import_module` arguments \
+                                       in a single `#[link]` attribute";
+                            sess.span_err(item.span(), msg);
+                            continue;
+                        }
+                        let Some(link_wasm_import_module) = item.value_str() else {
+                            let msg = "wasm import module must be of the form \
+                                       `wasm_import_module = \"string\"`";
+                            sess.span_err(item.span(), msg);
+                            continue;
+                        };
+                        wasm_import_module = Some((link_wasm_import_module, item.span()));
+                    }
+                    _ => {
+                        let msg = "unexpected `#[link]` argument, expected one of: \
+                                   name, kind, modifiers, cfg, wasm_import_module";
                         sess.span_err(item.span(), msg);
                     }
-                } else {
-                    let msg = "must be of the form `#[link(modifiers = \"...\")]`";
-                    sess.span_err(item.span(), msg);
                 }
             }
 
-            if modifiers_count > 1 {
-                let msg = "multiple `modifiers` arguments in a single `#[link]` attribute";
-                sess.span_err(m.span, msg);
+            // Do this outside the above loop so we don't depend on modifiers coming after kinds
+            let mut verbatim = None;
+            if let Some((modifiers, span)) = modifiers {
+                for modifier in modifiers.as_str().split(',') {
+                    let (modifier, value) = match modifier.strip_prefix(&['+', '-']) {
+                        Some(m) => (m, modifier.starts_with('+')),
+                        None => {
+                            sess.span_err(
+                                span,
+                                "invalid linking modifier syntax, expected '+' or '-' prefix \
+                                before one of: bundle, verbatim, whole-archive, as-needed",
+                            );
+                            continue;
+                        }
+                    };
+
+                    macro report_unstable_modifier($feature: ident) {
+                        if !features.$feature {
+                            feature_err(
+                                &sess.parse_sess,
+                                sym::$feature,
+                                span,
+                                &format!("linking modifier `{modifier}` is unstable"),
+                            )
+                            .emit();
+                        }
+                    }
+                    let assign_modifier = |dst: &mut Option<bool>| {
+                        if dst.is_some() {
+                            let msg = format!(
+                                "multiple `{modifier}` modifiers in a single `modifiers` argument"
+                            );
+                            sess.span_err(span, &msg);
+                        } else {
+                            *dst = Some(value);
+                        }
+                    };
+                    match (modifier, &mut kind) {
+                        ("bundle", Some(NativeLibKind::Static { bundle, .. })) => {
+                            assign_modifier(bundle)
+                        }
+                        ("bundle", _) => {
+                            sess.span_err(
+                                span,
+                                "linking modifier `bundle` is only compatible with \
+                                 `static` linking kind",
+                            );
+                        }
+
+                        ("verbatim", _) => {
+                            report_unstable_modifier!(native_link_modifiers_verbatim);
+                            assign_modifier(&mut verbatim)
+                        }
+
+                        ("whole-archive", Some(NativeLibKind::Static { whole_archive, .. })) => {
+                            assign_modifier(whole_archive)
+                        }
+                        ("whole-archive", _) => {
+                            sess.span_err(
+                                span,
+                                "linking modifier `whole-archive` is only compatible with \
+                                 `static` linking kind",
+                            );
+                        }
+
+                        ("as-needed", Some(NativeLibKind::Dylib { as_needed }))
+                        | ("as-needed", Some(NativeLibKind::Framework { as_needed })) => {
+                            report_unstable_modifier!(native_link_modifiers_as_needed);
+                            assign_modifier(as_needed)
+                        }
+                        ("as-needed", _) => {
+                            sess.span_err(
+                                span,
+                                "linking modifier `as-needed` is only compatible with \
+                                 `dylib` and `framework` linking kinds",
+                            );
+                        }
+
+                        _ => {
+                            sess.span_err(
+                                span,
+                                format!(
+                                    "unknown linking modifier `{modifier}`, expected one of: \
+                                     bundle, verbatim, whole-archive, as-needed"
+                                ),
+                            );
+                        }
+                    }
+                }
             }
 
-            // In general we require #[link(name = "...")] but we allow
-            // #[link(wasm_import_module = "...")] without the `name`.
-            let requires_name = kind_specified || lib.wasm_import_module.is_none();
-            if lib.name.is_none() && requires_name {
+            if let Some((_, span)) = wasm_import_module {
+                if name.is_some() || kind.is_some() || modifiers.is_some() || cfg.is_some() {
+                    let msg = "`wasm_import_module` is incompatible with \
+                               other arguments in `#[link]` attributes";
+                    sess.span_err(span, msg);
+                }
+            } else if name.is_none() {
                 struct_span_err!(
                     sess,
                     m.span,
                     E0459,
-                    "`#[link(...)]` specified without \
-                                  `name = \"foo\"`"
+                    "`#[link]` attribute requires a `name = \"string\"` argument"
                 )
                 .span_label(m.span, "missing `name` argument")
                 .emit();
             }
 
-            if lib.kind == NativeLibKind::RawDylib {
-                lib.dll_imports.extend(
+            let dll_imports = match kind {
+                Some(NativeLibKind::RawDylib) => {
+                    if let Some((name, span)) = name && name.as_str().contains('\0') {
+                        sess.span_err(
+                            span,
+                            "link name must not contain NUL characters if link kind is `raw-dylib`",
+                        );
+                    }
                     foreign_mod_items
                         .iter()
-                        .map(|child_item| self.build_dll_import(abi, child_item)),
-                );
-            }
-
-            self.register_native_lib(Some(m.span), lib);
-        }
-    }
-
-    fn register_native_lib(&mut self, span: Option<Span>, lib: NativeLib) {
-        if lib.name.as_ref().map_or(false, |&s| s == kw::Empty) {
-            match span {
-                Some(span) => {
-                    struct_span_err!(
-                        self.tcx.sess,
-                        span,
-                        E0454,
-                        "`#[link(name = \"\")]` given with empty name"
-                    )
-                    .span_label(span, "empty name given")
-                    .emit();
+                        .map(|child_item| self.build_dll_import(abi, child_item))
+                        .collect()
                 }
-                None => {
-                    self.tcx.sess.err("empty library name given via `-l`");
-                }
-            }
-            return;
-        }
-        let is_osx = self.tcx.sess.target.is_like_osx;
-        if matches!(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();
-                }
-                None => {
-                    self.tcx.sess.err(msg);
-                }
-            }
-        }
-        if lib.cfg.is_some() && !self.tcx.features().link_cfg {
-            feature_err(
-                &self.tcx.sess.parse_sess,
-                sym::link_cfg,
-                span.unwrap(),
-                "kind=\"link_cfg\" is unstable",
-            )
-            .emit();
-        }
-        // this just unwraps lib.name; we already established that it isn't empty above.
-        if let (NativeLibKind::RawDylib, Some(lib_name)) = (lib.kind, lib.name) {
-            let Some(span) = span else {
-                bug!("raw-dylib libraries are not supported on the command line");
+                _ => Vec::new(),
             };
-
-            if !self.tcx.sess.target.options.is_like_windows {
-                self.tcx.sess.span_fatal(
-                    span,
-                    "`#[link(...)]` with `kind = \"raw-dylib\"` only supported on Windows",
-                );
-            }
-
-            if lib_name.as_str().contains('\0') {
-                self.tcx.sess.span_err(span, "library name may not contain NUL characters");
-            }
-
-            if !self.tcx.features().raw_dylib {
-                feature_err(
-                    &self.tcx.sess.parse_sess,
-                    sym::raw_dylib,
-                    span,
-                    "kind=\"raw-dylib\" is unstable",
-                )
-                .emit();
-            }
+            self.libs.push(NativeLib {
+                name: name.map(|(name, _)| name),
+                kind: kind.unwrap_or(NativeLibKind::Unspecified),
+                cfg,
+                foreign_module: Some(it.def_id.to_def_id()),
+                wasm_import_module: wasm_import_module.map(|(name, _)| name),
+                verbatim,
+                dll_imports,
+            });
         }
-
-        self.libs.push(lib);
     }
 
     // Process libs passed on the command line
@@ -335,6 +347,10 @@
         // First, check for errors
         let mut renames = FxHashSet::default();
         for lib in &self.tcx.sess.opts.libs {
+            if let NativeLibKind::Framework { .. } = lib.kind && !self.tcx.sess.target.is_like_osx {
+                // Cannot check this when parsing options because the target is not yet available.
+                self.tcx.sess.err("library kind `framework` is only supported on Apple targets");
+            }
             if let Some(ref new_name) = lib.new_name {
                 let any_duplicate = self
                     .libs
@@ -342,19 +358,19 @@
                     .filter_map(|lib| lib.name.as_ref())
                     .any(|n| n.as_str() == lib.name);
                 if new_name.is_empty() {
-                    self.tcx.sess.err(&format!(
+                    self.tcx.sess.err(format!(
                         "an empty renaming target was specified for library `{}`",
                         lib.name
                     ));
                 } else if !any_duplicate {
-                    self.tcx.sess.err(&format!(
+                    self.tcx.sess.err(format!(
                         "renaming of the library `{}` was specified, \
                                                 however this crate contains no `#[link(...)]` \
                                                 attributes referencing this library",
                         lib.name
                     ));
                 } else if !renames.insert(&lib.name) {
-                    self.tcx.sess.err(&format!(
+                    self.tcx.sess.err(format!(
                         "multiple renamings were \
                                                 specified for library `{}`",
                         lib.name
@@ -405,7 +421,7 @@
             if existing.is_empty() {
                 // Add if not found
                 let new_name: Option<&str> = passed_lib.new_name.as_deref();
-                let lib = NativeLib {
+                self.libs.push(NativeLib {
                     name: Some(Symbol::intern(new_name.unwrap_or(&passed_lib.name))),
                     kind: passed_lib.kind,
                     cfg: None,
@@ -413,8 +429,7 @@
                     wasm_import_module: None,
                     verbatim: passed_lib.verbatim,
                     dll_imports: Vec::new(),
-                };
-                self.register_native_lib(None, lib);
+                });
             } else {
                 // Move all existing libraries with the same name to the
                 // end of the command line.
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index b25522c..c1ded99 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -1,36 +1,33 @@
 // Decoding metadata from a single crate's metadata
 
 use crate::creader::{CStore, CrateMetadataRef};
-use crate::rmeta::table::{FixedSizeEncoding, Table};
 use crate::rmeta::*;
 
 use rustc_ast as ast;
 use rustc_ast::ptr::P;
-use rustc_attr as attr;
 use rustc_data_structures::captures::Captures;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::svh::Svh;
 use rustc_data_structures::sync::{Lock, LockGuard, Lrc, OnceCell};
 use rustc_data_structures::unhash::UnhashMap;
 use rustc_expand::base::{SyntaxExtension, SyntaxExtensionKind};
-use rustc_expand::proc_macro::{AttrProcMacro, BangProcMacro, ProcMacroDerive};
+use rustc_expand::proc_macro::{AttrProcMacro, BangProcMacro, DeriveProcMacro};
 use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
 use rustc_hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE};
 use rustc_hir::definitions::{DefKey, DefPath, DefPathData, DefPathHash};
 use rustc_hir::diagnostic_items::DiagnosticItems;
 use rustc_hir::lang_items;
 use rustc_index::vec::{Idx, IndexVec};
-use rustc_middle::arena::ArenaAllocatable;
 use rustc_middle::metadata::ModChild;
 use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo};
-use rustc_middle::middle::stability::DeprecationEntry;
 use rustc_middle::mir::interpret::{AllocDecodingSession, AllocDecodingState};
 use rustc_middle::thir;
 use rustc_middle::ty::codec::TyDecoder;
 use rustc_middle::ty::fast_reject::SimplifiedType;
 use rustc_middle::ty::GeneratorDiagnosticData;
-use rustc_middle::ty::{self, Ty, TyCtxt, Visibility};
-use rustc_serialize::{opaque, Decodable, Decoder};
+use rustc_middle::ty::{self, ParameterizedOverTcx, Ty, TyCtxt, Visibility};
+use rustc_serialize::opaque::MemDecoder;
+use rustc_serialize::{Decodable, Decoder};
 use rustc_session::cstore::{
     CrateSource, ExternCrate, ForeignModule, LinkagePreference, NativeLib,
 };
@@ -42,6 +39,7 @@
 
 use proc_macro::bridge::client::ProcMacro;
 use std::io;
+use std::iter::TrustedLen;
 use std::mem;
 use std::num::NonZeroUsize;
 use std::path::Path;
@@ -57,7 +55,7 @@
 /// A `MetadataBlob` internally is just a reference counted pointer to
 /// the actual data, so cloning it is cheap.
 #[derive(Clone)]
-crate struct MetadataBlob(Lrc<MetadataRef>);
+pub(crate) struct MetadataBlob(Lrc<MetadataRef>);
 
 // This is needed so we can create an OwningRef into the blob.
 // The data behind a `MetadataBlob` has a stable address because it is
@@ -78,28 +76,27 @@
 // local crate numbers (as generated during this session). Each external
 // crate may refer to types in other external crates, and each has their
 // own crate numbers.
-crate type CrateNumMap = IndexVec<CrateNum, CrateNum>;
+pub(crate) type CrateNumMap = IndexVec<CrateNum, CrateNum>;
 
-crate struct CrateMetadata {
+pub(crate) struct CrateMetadata {
     /// The primary crate data - binary metadata blob.
     blob: MetadataBlob,
 
     // --- Some data pre-decoded from the metadata blob, usually for performance ---
-    /// Properties of the whole crate.
     /// NOTE(eddyb) we pass `'static` to a `'tcx` parameter because this
     /// lifetime is only used behind `Lazy`, and therefore acts like a
     /// universal (`for<'tcx>`), that is paired up with whichever `TyCtxt`
     /// is being used to decode those values.
-    root: CrateRoot<'static>,
+    root: CrateRoot,
     /// Trait impl data.
     /// FIXME: Used only from queries and can use query cache,
     /// so pre-decoding can probably be avoided.
-    trait_impls: FxHashMap<(u32, DefIndex), Lazy<[(DefIndex, Option<SimplifiedType>)]>>,
+    trait_impls: FxHashMap<(u32, DefIndex), LazyArray<(DefIndex, Option<SimplifiedType>)>>,
     /// Inherent impls which do not follow the normal coherence rules.
     ///
     /// These can be introduced using either `#![rustc_coherence_is_core]`
     /// or `#[rustc_allow_incoherent_impl]`.
-    incoherent_impls: FxHashMap<SimplifiedType, Lazy<[DefIndex]>>,
+    incoherent_impls: FxHashMap<SimplifiedType, LazyArray<DefIndex>>,
     /// 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.
@@ -158,7 +155,7 @@
 }
 
 pub(super) struct DecodeContext<'a, 'tcx> {
-    opaque: opaque::Decoder<'a>,
+    opaque: MemDecoder<'a>,
     cdata: Option<CrateMetadataRef<'a>>,
     blob: &'a MetadataBlob,
     sess: Option<&'tcx Session>,
@@ -190,7 +187,7 @@
     fn decoder(self, pos: usize) -> DecodeContext<'a, 'tcx> {
         let tcx = self.tcx();
         DecodeContext {
-            opaque: opaque::Decoder::new(self.blob(), pos),
+            opaque: MemDecoder::new(self.blob(), pos),
             cdata: self.cdata(),
             blob: self.blob(),
             sess: self.sess().or(tcx.map(|tcx| tcx.sess)),
@@ -265,138 +262,61 @@
     }
 }
 
-impl<'a, 'tcx, T: Decodable<DecodeContext<'a, 'tcx>>> Lazy<T> {
-    fn decode<M: Metadata<'a, 'tcx>>(self, metadata: M) -> T {
+impl<T: ParameterizedOverTcx> LazyValue<T> {
+    fn decode<'a, 'tcx, M: Metadata<'a, 'tcx>>(self, metadata: M) -> T::Value<'tcx>
+    where
+        T::Value<'tcx>: Decodable<DecodeContext<'a, 'tcx>>,
+    {
         let mut dcx = metadata.decoder(self.position.get());
         dcx.lazy_state = LazyState::NodeStart(self.position);
-        T::decode(&mut dcx)
+        T::Value::decode(&mut dcx)
     }
 }
 
-impl<'a: 'x, 'tcx: 'x, 'x, T: Decodable<DecodeContext<'a, 'tcx>>> Lazy<[T]> {
-    fn decode<M: Metadata<'a, 'tcx>>(
+struct DecodeIterator<'a, 'tcx, T> {
+    elem_counter: std::ops::Range<usize>,
+    dcx: DecodeContext<'a, 'tcx>,
+    _phantom: PhantomData<fn() -> T>,
+}
+
+impl<'a, 'tcx, T: Decodable<DecodeContext<'a, 'tcx>>> Iterator for DecodeIterator<'a, 'tcx, T> {
+    type Item = T;
+
+    #[inline(always)]
+    fn next(&mut self) -> Option<Self::Item> {
+        self.elem_counter.next().map(|_| T::decode(&mut self.dcx))
+    }
+
+    #[inline(always)]
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        self.elem_counter.size_hint()
+    }
+}
+
+impl<'a, 'tcx, T: Decodable<DecodeContext<'a, 'tcx>>> ExactSizeIterator
+    for DecodeIterator<'a, 'tcx, T>
+{
+    fn len(&self) -> usize {
+        self.elem_counter.len()
+    }
+}
+
+unsafe impl<'a, 'tcx, T: Decodable<DecodeContext<'a, 'tcx>>> TrustedLen
+    for DecodeIterator<'a, 'tcx, T>
+{
+}
+
+impl<T: ParameterizedOverTcx> LazyArray<T> {
+    fn decode<'a, 'tcx, M: Metadata<'a, 'tcx>>(
         self,
         metadata: M,
-    ) -> impl ExactSizeIterator<Item = T> + Captures<'a> + Captures<'tcx> + 'x {
+    ) -> DecodeIterator<'a, 'tcx, T::Value<'tcx>>
+    where
+        T::Value<'tcx>: Decodable<DecodeContext<'a, 'tcx>>,
+    {
         let mut dcx = metadata.decoder(self.position.get());
         dcx.lazy_state = LazyState::NodeStart(self.position);
-        (0..self.meta).map(move |_| T::decode(&mut dcx))
-    }
-}
-
-trait LazyQueryDecodable<'a, 'tcx, T> {
-    fn decode_query(
-        self,
-        cdata: CrateMetadataRef<'a>,
-        tcx: TyCtxt<'tcx>,
-        err: impl FnOnce() -> !,
-    ) -> T;
-}
-
-impl<'a, 'tcx, T> LazyQueryDecodable<'a, 'tcx, T> for T {
-    fn decode_query(self, _: CrateMetadataRef<'a>, _: TyCtxt<'tcx>, _: impl FnOnce() -> !) -> T {
-        self
-    }
-}
-
-impl<'a, 'tcx, T> LazyQueryDecodable<'a, 'tcx, T> for Option<T> {
-    fn decode_query(self, _: CrateMetadataRef<'a>, _: TyCtxt<'tcx>, err: impl FnOnce() -> !) -> T {
-        if let Some(l) = self { l } else { err() }
-    }
-}
-
-impl<'a, 'tcx, T> LazyQueryDecodable<'a, 'tcx, T> for Option<Lazy<T>>
-where
-    T: Decodable<DecodeContext<'a, 'tcx>>,
-{
-    fn decode_query(
-        self,
-        cdata: CrateMetadataRef<'a>,
-        tcx: TyCtxt<'tcx>,
-        err: impl FnOnce() -> !,
-    ) -> T {
-        if let Some(l) = self { l.decode((cdata, tcx)) } else { err() }
-    }
-}
-
-impl<'a, 'tcx, T> LazyQueryDecodable<'a, 'tcx, &'tcx T> for Option<Lazy<T>>
-where
-    T: Decodable<DecodeContext<'a, 'tcx>>,
-    T: ArenaAllocatable<'tcx>,
-{
-    fn decode_query(
-        self,
-        cdata: CrateMetadataRef<'a>,
-        tcx: TyCtxt<'tcx>,
-        err: impl FnOnce() -> !,
-    ) -> &'tcx T {
-        if let Some(l) = self { tcx.arena.alloc(l.decode((cdata, tcx))) } else { err() }
-    }
-}
-
-impl<'a, 'tcx, T> LazyQueryDecodable<'a, 'tcx, Option<T>> for Option<Lazy<T>>
-where
-    T: Decodable<DecodeContext<'a, 'tcx>>,
-{
-    fn decode_query(
-        self,
-        cdata: CrateMetadataRef<'a>,
-        tcx: TyCtxt<'tcx>,
-        _err: impl FnOnce() -> !,
-    ) -> Option<T> {
-        self.map(|l| l.decode((cdata, tcx)))
-    }
-}
-
-impl<'a, 'tcx, T, E> LazyQueryDecodable<'a, 'tcx, Result<Option<T>, E>> for Option<Lazy<T>>
-where
-    T: Decodable<DecodeContext<'a, 'tcx>>,
-{
-    fn decode_query(
-        self,
-        cdata: CrateMetadataRef<'a>,
-        tcx: TyCtxt<'tcx>,
-        _err: impl FnOnce() -> !,
-    ) -> Result<Option<T>, E> {
-        Ok(self.map(|l| l.decode((cdata, tcx))))
-    }
-}
-
-impl<'a, 'tcx, T> LazyQueryDecodable<'a, 'tcx, &'tcx [T]> for Option<Lazy<[T], usize>>
-where
-    T: Decodable<DecodeContext<'a, 'tcx>> + Copy,
-{
-    fn decode_query(
-        self,
-        cdata: CrateMetadataRef<'a>,
-        tcx: TyCtxt<'tcx>,
-        _err: impl FnOnce() -> !,
-    ) -> &'tcx [T] {
-        if let Some(l) = self { tcx.arena.alloc_from_iter(l.decode((cdata, tcx))) } else { &[] }
-    }
-}
-
-impl<'a, 'tcx> LazyQueryDecodable<'a, 'tcx, Option<DeprecationEntry>>
-    for Option<Lazy<attr::Deprecation>>
-{
-    fn decode_query(
-        self,
-        cdata: CrateMetadataRef<'a>,
-        tcx: TyCtxt<'tcx>,
-        _err: impl FnOnce() -> !,
-    ) -> Option<DeprecationEntry> {
-        self.map(|l| l.decode((cdata, tcx))).map(DeprecationEntry::external)
-    }
-}
-
-impl<'a, 'tcx> LazyQueryDecodable<'a, 'tcx, Option<DefId>> for Option<RawDefId> {
-    fn decode_query(
-        self,
-        cdata: CrateMetadataRef<'a>,
-        _: TyCtxt<'tcx>,
-        _: impl FnOnce() -> !,
-    ) -> Option<DefId> {
-        self.map(|raw_def_id| raw_def_id.decode(cdata))
+        DecodeIterator { elem_counter: (0..self.num_elems), dcx, _phantom: PhantomData }
     }
 }
 
@@ -423,7 +343,8 @@
         self.cdata().map_encoded_cnum_to_current(cnum)
     }
 
-    fn read_lazy_with_meta<T: ?Sized + LazyMeta>(&mut self, meta: T::Meta) -> Lazy<T> {
+    #[inline]
+    fn read_lazy_offset_then<T>(&mut self, f: impl Fn(NonZeroUsize) -> T) -> T {
         let distance = self.read_usize();
         let position = match self.lazy_state {
             LazyState::NoNode => bug!("read_lazy_with_meta: outside of a metadata node"),
@@ -434,8 +355,21 @@
             }
             LazyState::Previous(last_pos) => last_pos.get() + distance,
         };
-        self.lazy_state = LazyState::Previous(NonZeroUsize::new(position).unwrap());
-        Lazy::from_position_and_meta(NonZeroUsize::new(position).unwrap(), meta)
+        let position = NonZeroUsize::new(position).unwrap();
+        self.lazy_state = LazyState::Previous(position);
+        f(position)
+    }
+
+    fn read_lazy<T>(&mut self) -> LazyValue<T> {
+        self.read_lazy_offset_then(|pos| LazyValue::from_position(pos))
+    }
+
+    fn read_lazy_array<T>(&mut self, len: usize) -> LazyArray<T> {
+        self.read_lazy_offset_then(|pos| LazyArray::from_position_and_num_elems(pos, len))
+    }
+
+    fn read_lazy_table<I, T>(&mut self, len: usize) -> LazyTable<I, T> {
+        self.read_lazy_offset_then(|pos| LazyTable::from_position_and_encoded_size(pos, len))
     }
 
     #[inline]
@@ -444,12 +378,14 @@
     }
 }
 
-impl<'a, 'tcx> TyDecoder<'tcx> for DecodeContext<'a, 'tcx> {
+impl<'a, 'tcx> TyDecoder for DecodeContext<'a, 'tcx> {
     const CLEAR_CROSS_CRATE: bool = true;
 
+    type I = TyCtxt<'tcx>;
+
     #[inline]
-    fn tcx(&self) -> TyCtxt<'tcx> {
-        self.tcx.expect("missing TyCtxt in DecodeContext")
+    fn interner(&self) -> Self::I {
+        self.tcx()
     }
 
     #[inline]
@@ -483,7 +419,7 @@
     where
         F: FnOnce(&mut Self) -> R,
     {
-        let new_opaque = opaque::Decoder::new(self.opaque.data, pos);
+        let new_opaque = MemDecoder::new(self.opaque.data, pos);
         let old_opaque = mem::replace(&mut self.opaque, new_opaque);
         let old_state = mem::replace(&mut self.lazy_state, LazyState::NoNode);
         let r = f(self);
@@ -714,60 +650,53 @@
     }
 }
 
-impl<'a, 'tcx, T: Decodable<DecodeContext<'a, 'tcx>>> Decodable<DecodeContext<'a, 'tcx>>
-    for Lazy<T>
-{
+impl<'a, 'tcx, T> Decodable<DecodeContext<'a, 'tcx>> for LazyValue<T> {
     fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> Self {
-        decoder.read_lazy_with_meta(())
+        decoder.read_lazy()
     }
 }
 
-impl<'a, 'tcx, T: Decodable<DecodeContext<'a, 'tcx>>> Decodable<DecodeContext<'a, 'tcx>>
-    for Lazy<[T]>
-{
+impl<'a, 'tcx, T> Decodable<DecodeContext<'a, 'tcx>> for LazyArray<T> {
     fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> Self {
         let len = decoder.read_usize();
-        if len == 0 { Lazy::empty() } else { decoder.read_lazy_with_meta(len) }
+        if len == 0 { LazyArray::empty() } else { decoder.read_lazy_array(len) }
     }
 }
 
-impl<'a, 'tcx, I: Idx, T> Decodable<DecodeContext<'a, 'tcx>> for Lazy<Table<I, T>>
-where
-    Option<T>: FixedSizeEncoding,
-{
+impl<'a, 'tcx, I: Idx, T> Decodable<DecodeContext<'a, 'tcx>> for LazyTable<I, T> {
     fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> Self {
         let len = decoder.read_usize();
-        decoder.read_lazy_with_meta(len)
+        decoder.read_lazy_table(len)
     }
 }
 
 implement_ty_decoder!(DecodeContext<'a, 'tcx>);
 
-impl<'tcx> MetadataBlob {
-    crate fn new(metadata_ref: MetadataRef) -> MetadataBlob {
+impl MetadataBlob {
+    pub(crate) fn new(metadata_ref: MetadataRef) -> MetadataBlob {
         MetadataBlob(Lrc::new(metadata_ref))
     }
 
-    crate fn is_compatible(&self) -> bool {
+    pub(crate) fn is_compatible(&self) -> bool {
         self.blob().starts_with(METADATA_HEADER)
     }
 
-    crate fn get_rustc_version(&self) -> String {
-        Lazy::<String>::from_position(NonZeroUsize::new(METADATA_HEADER.len() + 4).unwrap())
+    pub(crate) fn get_rustc_version(&self) -> String {
+        LazyValue::<String>::from_position(NonZeroUsize::new(METADATA_HEADER.len() + 4).unwrap())
             .decode(self)
     }
 
-    crate fn get_root(&self) -> CrateRoot<'tcx> {
+    pub(crate) fn get_root(&self) -> CrateRoot {
         let slice = &self.blob()[..];
         let offset = METADATA_HEADER.len();
         let pos = (((slice[offset + 0] as u32) << 24)
             | ((slice[offset + 1] as u32) << 16)
             | ((slice[offset + 2] as u32) << 8)
             | ((slice[offset + 3] as u32) << 0)) as usize;
-        Lazy::<CrateRoot<'tcx>>::from_position(NonZeroUsize::new(pos).unwrap()).decode(self)
+        LazyValue::<CrateRoot>::from_position(NonZeroUsize::new(pos).unwrap()).decode(self)
     }
 
-    crate fn list_crate_metadata(&self, out: &mut dyn io::Write) -> io::Result<()> {
+    pub(crate) fn list_crate_metadata(&self, out: &mut dyn io::Write) -> io::Result<()> {
         let root = self.get_root();
         writeln!(out, "Crate info:")?;
         writeln!(out, "name {}{}", root.name, root.extra_filename)?;
@@ -791,28 +720,28 @@
     }
 }
 
-impl CrateRoot<'_> {
-    crate fn is_proc_macro_crate(&self) -> bool {
+impl CrateRoot {
+    pub(crate) fn is_proc_macro_crate(&self) -> bool {
         self.proc_macro_data.is_some()
     }
 
-    crate fn name(&self) -> Symbol {
+    pub(crate) fn name(&self) -> Symbol {
         self.name
     }
 
-    crate fn hash(&self) -> Svh {
+    pub(crate) fn hash(&self) -> Svh {
         self.hash
     }
 
-    crate fn stable_crate_id(&self) -> StableCrateId {
+    pub(crate) fn stable_crate_id(&self) -> StableCrateId {
         self.stable_crate_id
     }
 
-    crate fn triple(&self) -> &TargetTriple {
+    pub(crate) fn triple(&self) -> &TargetTriple {
         &self.triple
     }
 
-    crate fn decode_crate_deps<'a>(
+    pub(crate) fn decode_crate_deps<'a>(
         &self,
         metadata: &'a MetadataBlob,
     ) -> impl ExactSizeIterator<Item = CrateDep> + Captures<'a> {
@@ -846,17 +775,8 @@
 
     fn opt_item_ident(self, item_index: DefIndex, sess: &Session) -> Option<Ident> {
         let name = self.opt_item_name(item_index)?;
-        let span = match self.root.tables.def_ident_span.get(self, item_index) {
-            Some(lazy_span) => lazy_span.decode((self, sess)),
-            None => {
-                // FIXME: this weird case of a name with no span is specific to `extern crate`
-                // items, which are supposed to be treated like `use` items and only be encoded
-                // to metadata as `Export`s, return `None` because that's what all the callers
-                // expect in this case.
-                assert_eq!(self.def_kind(item_index), DefKind::ExternCrate);
-                return None;
-            }
-        };
+        let span =
+            self.root.tables.def_ident_span.get(self, item_index).unwrap().decode((self, sess));
         Some(Ident::new(name, span))
     }
 
@@ -911,7 +831,7 @@
                     attributes.iter().cloned().map(Symbol::intern).collect::<Vec<_>>();
                 (
                     trait_name,
-                    SyntaxExtensionKind::Derive(Box::new(ProcMacroDerive { client })),
+                    SyntaxExtensionKind::Derive(Box::new(DeriveProcMacro { client })),
                     helper_attrs,
                 )
             }
@@ -963,7 +883,7 @@
                 .tables
                 .children
                 .get(self, index)
-                .unwrap_or_else(Lazy::empty)
+                .unwrap_or_else(LazyArray::empty)
                 .decode(self)
                 .map(|index| ty::FieldDef {
                     did: self.local_def_id(index),
@@ -996,7 +916,7 @@
                 .tables
                 .children
                 .get(self, item_id)
-                .unwrap_or_else(Lazy::empty)
+                .unwrap_or_else(LazyArray::empty)
                 .decode(self)
                 .map(|index| self.get_variant(&self.kind(index), index, did))
                 .collect()
@@ -1016,7 +936,7 @@
     }
 
     fn get_trait_item_def_id(self, id: DefIndex) -> Option<DefId> {
-        self.root.tables.trait_item_def_id.get(self, id).map(|d| d.decode(self))
+        self.root.tables.trait_item_def_id.get(self, id).map(|d| d.decode_from_cdata(self))
     }
 
     fn get_expn_that_defined(self, id: DefIndex, sess: &Session) -> ExpnId {
@@ -1202,7 +1122,7 @@
             .tables
             .children
             .get(self, id)
-            .unwrap_or_else(Lazy::empty)
+            .unwrap_or_else(LazyArray::empty)
             .decode((self, sess))
             .map(move |child_index| self.local_def_id(child_index))
     }
@@ -1278,7 +1198,7 @@
             .tables
             .children
             .get(self, id)
-            .unwrap_or_else(Lazy::empty)
+            .unwrap_or_else(LazyArray::empty)
             .decode(self)
             .map(move |index| respan(self.get_span(index, sess), self.item_name(index)))
     }
@@ -1288,7 +1208,7 @@
             .tables
             .children
             .get(self, id)
-            .unwrap_or_else(Lazy::empty)
+            .unwrap_or_else(LazyArray::empty)
             .decode(self)
             .map(move |field_index| self.get_visibility(field_index))
     }
@@ -1303,7 +1223,7 @@
                 .tables
                 .inherent_impls
                 .get(self, id)
-                .unwrap_or_else(Lazy::empty)
+                .unwrap_or_else(LazyArray::empty)
                 .decode(self)
                 .map(|index| self.local_def_id(index)),
         )
@@ -1318,7 +1238,7 @@
                 .tables
                 .inherent_impls
                 .get(self, ty_index)
-                .unwrap_or_else(Lazy::empty)
+                .unwrap_or_else(LazyArray::empty)
                 .decode(self)
                 .map(move |impl_index| (ty_def_id, self.local_def_id(impl_index)))
         })
@@ -1558,6 +1478,8 @@
             .filter(|_| {
                 // Only spend time on further checks if we have what to translate *to*.
                 sess.opts.real_rust_source_base_dir.is_some()
+                    // Some tests need the translation to be always skipped.
+                    && sess.opts.debugging_opts.translate_remapped_path_to_local_path
             })
             .filter(|virtual_dir| {
                 // Don't translate away `/rustc/$hash` if we're still remapping to it,
@@ -1639,10 +1561,10 @@
                         src_hash,
                         start_pos,
                         end_pos,
-                        mut lines,
-                        mut multibyte_chars,
-                        mut non_narrow_chars,
-                        mut normalized_pos,
+                        lines,
+                        multibyte_chars,
+                        non_narrow_chars,
+                        normalized_pos,
                         name_hash,
                         ..
                     } = source_file_to_import;
@@ -1679,24 +1601,6 @@
 
                     let source_length = (end_pos - start_pos).to_usize();
 
-                    // Translate line-start positions and multibyte character
-                    // position into frame of reference local to file.
-                    // `SourceMap::new_imported_source_file()` will then translate those
-                    // coordinates to their new global frame of reference when the
-                    // offset of the SourceFile is known.
-                    for pos in &mut lines {
-                        *pos = *pos - start_pos;
-                    }
-                    for mbc in &mut multibyte_chars {
-                        mbc.pos = mbc.pos - start_pos;
-                    }
-                    for swc in &mut non_narrow_chars {
-                        *swc = *swc - start_pos;
-                    }
-                    for np in &mut normalized_pos {
-                        np.pos = np.pos - start_pos;
-                    }
-
                     let local_version = sess.source_map().new_imported_source_file(
                         name,
                         src_hash,
@@ -1752,14 +1656,18 @@
     fn get_may_have_doc_links(self, index: DefIndex) -> bool {
         self.root.tables.may_have_doc_links.get(self, index).is_some()
     }
+
+    fn get_is_intrinsic(self, index: DefIndex) -> bool {
+        self.root.tables.is_intrinsic.get(self, index).is_some()
+    }
 }
 
 impl CrateMetadata {
-    crate fn new(
+    pub(crate) fn new(
         sess: &Session,
         cstore: &CStore,
         blob: MetadataBlob,
-        root: CrateRoot<'static>,
+        root: CrateRoot,
         raw_proc_macros: Option<&'static [ProcMacro]>,
         cnum: CrateNum,
         cnum_map: CrateNumMap,
@@ -1815,15 +1723,15 @@
         cdata
     }
 
-    crate fn dependencies(&self) -> LockGuard<'_, Vec<CrateNum>> {
+    pub(crate) fn dependencies(&self) -> LockGuard<'_, Vec<CrateNum>> {
         self.dependencies.borrow()
     }
 
-    crate fn add_dependency(&self, cnum: CrateNum) {
+    pub(crate) fn add_dependency(&self, cnum: CrateNum) {
         self.dependencies.borrow_mut().push(cnum);
     }
 
-    crate fn update_extern_crate(&self, new_extern_crate: ExternCrate) -> bool {
+    pub(crate) fn update_extern_crate(&self, new_extern_crate: ExternCrate) -> bool {
         let mut extern_crate = self.extern_crate.borrow_mut();
         let update = Some(new_extern_crate.rank()) > extern_crate.as_ref().map(ExternCrate::rank);
         if update {
@@ -1832,59 +1740,59 @@
         update
     }
 
-    crate fn source(&self) -> &CrateSource {
+    pub(crate) fn source(&self) -> &CrateSource {
         &*self.source
     }
 
-    crate fn dep_kind(&self) -> CrateDepKind {
+    pub(crate) fn dep_kind(&self) -> CrateDepKind {
         *self.dep_kind.lock()
     }
 
-    crate fn update_dep_kind(&self, f: impl FnOnce(CrateDepKind) -> CrateDepKind) {
+    pub(crate) fn update_dep_kind(&self, f: impl FnOnce(CrateDepKind) -> CrateDepKind) {
         self.dep_kind.with_lock(|dep_kind| *dep_kind = f(*dep_kind))
     }
 
-    crate fn panic_strategy(&self) -> PanicStrategy {
+    pub(crate) fn panic_strategy(&self) -> PanicStrategy {
         self.root.panic_strategy
     }
 
-    crate fn needs_panic_runtime(&self) -> bool {
+    pub(crate) fn needs_panic_runtime(&self) -> bool {
         self.root.needs_panic_runtime
     }
 
-    crate fn is_panic_runtime(&self) -> bool {
+    pub(crate) fn is_panic_runtime(&self) -> bool {
         self.root.panic_runtime
     }
 
-    crate fn is_profiler_runtime(&self) -> bool {
+    pub(crate) fn is_profiler_runtime(&self) -> bool {
         self.root.profiler_runtime
     }
 
-    crate fn needs_allocator(&self) -> bool {
+    pub(crate) fn needs_allocator(&self) -> bool {
         self.root.needs_allocator
     }
 
-    crate fn has_global_allocator(&self) -> bool {
+    pub(crate) fn has_global_allocator(&self) -> bool {
         self.root.has_global_allocator
     }
 
-    crate fn has_default_lib_allocator(&self) -> bool {
+    pub(crate) fn has_default_lib_allocator(&self) -> bool {
         self.root.has_default_lib_allocator
     }
 
-    crate fn is_proc_macro_crate(&self) -> bool {
+    pub(crate) fn is_proc_macro_crate(&self) -> bool {
         self.root.is_proc_macro_crate()
     }
 
-    crate fn name(&self) -> Symbol {
+    pub(crate) fn name(&self) -> Symbol {
         self.root.name
     }
 
-    crate fn stable_crate_id(&self) -> StableCrateId {
+    pub(crate) fn stable_crate_id(&self) -> StableCrateId {
         self.root.stable_crate_id
     }
 
-    crate fn hash(&self) -> Svh {
+    pub(crate) fn hash(&self) -> Svh {
         self.root.hash
     }
 
diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
index 9f7ef39..0bea2a1 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
@@ -1,14 +1,16 @@
-use super::LazyQueryDecodable;
 use crate::creader::{CStore, LoadedMacro};
 use crate::foreign_modules;
 use crate::native_libs;
 
 use rustc_ast as ast;
+use rustc_attr::Deprecation;
 use rustc_hir::def::{CtorKind, DefKind, Res};
 use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LOCAL_CRATE};
 use rustc_hir::definitions::{DefKey, DefPath, DefPathHash};
+use rustc_middle::arena::ArenaAllocatable;
 use rustc_middle::metadata::ModChild;
 use rustc_middle::middle::exported_symbols::ExportedSymbol;
+use rustc_middle::middle::stability::DeprecationEntry;
 use rustc_middle::ty::fast_reject::SimplifiedType;
 use rustc_middle::ty::query::{ExternProviders, Providers};
 use rustc_middle::ty::{self, TyCtxt, Visibility};
@@ -23,15 +25,80 @@
 use smallvec::SmallVec;
 use std::any::Any;
 
+use super::{Decodable, DecodeContext, DecodeIterator};
+
+trait ProcessQueryValue<'tcx, T> {
+    fn process_decoded(self, _tcx: TyCtxt<'tcx>, _err: impl Fn() -> !) -> T;
+}
+
+impl<T> ProcessQueryValue<'_, Option<T>> for Option<T> {
+    #[inline(always)]
+    fn process_decoded(self, _tcx: TyCtxt<'_>, _err: impl Fn() -> !) -> Option<T> {
+        self
+    }
+}
+
+impl<T> ProcessQueryValue<'_, T> for Option<T> {
+    #[inline(always)]
+    fn process_decoded(self, _tcx: TyCtxt<'_>, err: impl Fn() -> !) -> T {
+        if let Some(value) = self { value } else { err() }
+    }
+}
+
+impl<'tcx, T: ArenaAllocatable<'tcx>> ProcessQueryValue<'tcx, &'tcx T> for Option<T> {
+    #[inline(always)]
+    fn process_decoded(self, tcx: TyCtxt<'tcx>, err: impl Fn() -> !) -> &'tcx T {
+        if let Some(value) = self { tcx.arena.alloc(value) } else { err() }
+    }
+}
+
+impl<T, E> ProcessQueryValue<'_, Result<Option<T>, E>> for Option<T> {
+    #[inline(always)]
+    fn process_decoded(self, _tcx: TyCtxt<'_>, _err: impl Fn() -> !) -> Result<Option<T>, E> {
+        Ok(self)
+    }
+}
+
+impl<'a, 'tcx, T: Copy + Decodable<DecodeContext<'a, 'tcx>>> ProcessQueryValue<'tcx, &'tcx [T]>
+    for Option<DecodeIterator<'a, 'tcx, T>>
+{
+    #[inline(always)]
+    fn process_decoded(self, tcx: TyCtxt<'tcx>, _err: impl Fn() -> !) -> &'tcx [T] {
+        if let Some(iter) = self { tcx.arena.alloc_from_iter(iter) } else { &[] }
+    }
+}
+
+impl ProcessQueryValue<'_, Option<DeprecationEntry>> for Option<Deprecation> {
+    #[inline(always)]
+    fn process_decoded(self, _tcx: TyCtxt<'_>, _err: impl Fn() -> !) -> Option<DeprecationEntry> {
+        self.map(DeprecationEntry::external)
+    }
+}
+
 macro_rules! provide_one {
     (<$lt:tt> $tcx:ident, $def_id:ident, $other:ident, $cdata:ident, $name:ident => { table }) => {
         provide_one! {
             <$lt> $tcx, $def_id, $other, $cdata, $name => {
-                $cdata.root.tables.$name.get($cdata, $def_id.index).decode_query(
-                    $cdata,
-                    $tcx,
-                    || panic!("{:?} does not have a {:?}", $def_id, stringify!($name)),
-                )
+                $cdata
+                    .root
+                    .tables
+                    .$name
+                    .get($cdata, $def_id.index)
+                    .map(|lazy| lazy.decode(($cdata, $tcx)))
+                    .process_decoded($tcx, || panic!("{:?} does not have a {:?}", $def_id, stringify!($name)))
+            }
+        }
+    };
+    (<$lt:tt> $tcx:ident, $def_id:ident, $other:ident, $cdata:ident, $name:ident => { table_direct }) => {
+        provide_one! {
+            <$lt> $tcx, $def_id, $other, $cdata, $name => {
+                // We don't decode `table_direct`, since it's not a Lazy, but an actual value
+                $cdata
+                    .root
+                    .tables
+                    .$name
+                    .get($cdata, $def_id.index)
+                    .process_decoded($tcx, || panic!("{:?} does not have a {:?}", $def_id, stringify!($name)))
             }
         }
     };
@@ -143,15 +210,15 @@
     lookup_deprecation_entry => { table }
     visibility => { table }
     unused_generic_params => { table }
-    opt_def_kind => { table }
+    opt_def_kind => { table_direct }
     impl_parent => { table }
-    impl_polarity => { table }
-    impl_defaultness => { table }
-    impl_constness => { table }
+    impl_polarity => { table_direct }
+    impl_defaultness => { table_direct }
+    constness => { table_direct }
     coerce_unsized_info => { table }
     mir_const_qualif => { table }
     rendered_const => { table }
-    asyncness => { table }
+    asyncness => { table_direct }
     fn_arg_names => { table }
     generator_kind => { table }
     trait_def => { table }
@@ -224,6 +291,7 @@
         tcx.arena.alloc_slice(&result)
     }
     defined_lib_features => { cdata.get_lib_features(tcx) }
+    is_intrinsic => { cdata.get_is_intrinsic(def_id.index) }
     defined_lang_items => { cdata.get_lang_items(tcx) }
     diagnostic_items => { cdata.get_diagnostic_items() }
     missing_lang_items => { cdata.get_missing_lang_items(tcx) }
diff --git a/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs b/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs
index d66f2b0..40c94b3 100644
--- a/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs
+++ b/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs
@@ -3,14 +3,19 @@
 use crate::rmeta::MetadataBlob;
 use rustc_data_structures::owning_ref::OwningRef;
 use rustc_hir::def_path_hash_map::{Config as HashMapConfig, DefPathHashMap};
-use rustc_serialize::{opaque, Decodable, Decoder, Encodable, Encoder};
+use rustc_middle::parameterized_over_tcx;
+use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
 use rustc_span::def_id::{DefIndex, DefPathHash};
 
-crate enum DefPathHashMapRef<'tcx> {
+pub(crate) enum DefPathHashMapRef<'tcx> {
     OwnedFromMetadata(odht::HashTable<HashMapConfig, OwningRef<MetadataBlob, [u8]>>),
     BorrowedFromTcx(&'tcx DefPathHashMap),
 }
 
+parameterized_over_tcx! {
+    DefPathHashMapRef,
+}
+
 impl DefPathHashMapRef<'_> {
     #[inline]
     pub fn def_path_hash_to_def_index(&self, def_path_hash: &DefPathHash) -> DefIndex {
@@ -24,12 +29,12 @@
 }
 
 impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for DefPathHashMapRef<'tcx> {
-    fn encode(&self, e: &mut EncodeContext<'a, 'tcx>) -> opaque::EncodeResult {
+    fn encode(&self, e: &mut EncodeContext<'a, 'tcx>) {
         match *self {
             DefPathHashMapRef::BorrowedFromTcx(def_path_hash_map) => {
                 let bytes = def_path_hash_map.raw_bytes();
-                e.emit_usize(bytes.len())?;
-                e.emit_raw_bytes(bytes)
+                e.emit_usize(bytes.len());
+                e.emit_raw_bytes(bytes);
             }
             DefPathHashMapRef::OwnedFromMetadata(_) => {
                 panic!("DefPathHashMap::OwnedFromMetadata variant only exists for deserialization")
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index 1de7dae..75286b8 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -1,10 +1,9 @@
 use crate::rmeta::def_path_hash_map::DefPathHashMapRef;
-use crate::rmeta::table::{FixedSizeEncoding, TableBuilder};
+use crate::rmeta::table::TableBuilder;
 use crate::rmeta::*;
 
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
-use rustc_data_structures::iter_from_generator;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_data_structures::sync::{join, par_iter, Lrc, ParallelIterator};
 use rustc_hir as hir;
@@ -14,46 +13,42 @@
 };
 use rustc_hir::definitions::DefPathData;
 use rustc_hir::intravisit::{self, Visitor};
-use rustc_hir::itemlikevisit::ItemLikeVisitor;
 use rustc_hir::lang_items;
 use rustc_hir::{AnonConst, GenericParamKind};
 use rustc_index::bit_set::GrowableBitSet;
-use rustc_index::vec::Idx;
 use rustc_middle::hir::nested_filter;
 use rustc_middle::middle::dependency_format::Linkage;
 use rustc_middle::middle::exported_symbols::{
     metadata_symbol_name, ExportedSymbol, SymbolExportInfo,
 };
 use rustc_middle::mir::interpret;
-use rustc_middle::thir;
 use rustc_middle::traits::specialization_graph;
 use rustc_middle::ty::codec::TyEncoder;
 use rustc_middle::ty::fast_reject::{self, SimplifiedType, TreatParams};
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::{self, SymbolName, Ty, TyCtxt};
-use rustc_serialize::{opaque, Encodable, Encoder};
+use rustc_serialize::opaque::MemEncoder;
+use rustc_serialize::{Encodable, Encoder};
 use rustc_session::config::CrateType;
 use rustc_session::cstore::{ForeignModule, LinkagePreference, NativeLib};
-use rustc_span::symbol::{sym, Ident, Symbol};
+use rustc_span::hygiene::{ExpnIndex, HygieneEncodeContext, MacroKind};
+use rustc_span::symbol::{sym, Symbol};
 use rustc_span::{
     self, DebuggerVisualizerFile, ExternalSource, FileName, SourceFile, Span, SyntaxContext,
 };
-use rustc_span::{
-    hygiene::{ExpnIndex, HygieneEncodeContext, MacroKind},
-    RealFileName,
-};
 use rustc_target::abi::VariantIdx;
+use std::borrow::Borrow;
 use std::hash::Hash;
+use std::iter;
 use std::num::NonZeroUsize;
-use std::path::Path;
 use tracing::{debug, trace};
 
 pub(super) struct EncodeContext<'a, 'tcx> {
-    opaque: opaque::Encoder,
+    opaque: MemEncoder,
     tcx: TyCtxt<'tcx>,
     feat: &'tcx rustc_feature::Features,
 
-    tables: TableBuilders<'tcx>,
+    tables: TableBuilders,
 
     lazy_state: LazyState,
     type_shorthands: FxHashMap<Ty<'tcx>, usize>,
@@ -85,27 +80,20 @@
 macro_rules! empty_proc_macro {
     ($self:ident) => {
         if $self.is_proc_macro {
-            return Lazy::empty();
+            return LazyArray::empty();
         }
     };
 }
 
 macro_rules! encoder_methods {
     ($($name:ident($ty:ty);)*) => {
-        $(fn $name(&mut self, value: $ty) -> Result<(), Self::Error> {
+        $(fn $name(&mut self, value: $ty) {
             self.opaque.$name(value)
         })*
     }
 }
 
 impl<'a, 'tcx> Encoder for EncodeContext<'a, 'tcx> {
-    type Error = <opaque::Encoder as Encoder>::Error;
-
-    #[inline]
-    fn emit_unit(&mut self) -> Result<(), Self::Error> {
-        Ok(())
-    }
-
     encoder_methods! {
         emit_usize(usize);
         emit_u128(u128);
@@ -130,65 +118,57 @@
     }
 }
 
-impl<'a, 'tcx, T: Encodable<EncodeContext<'a, 'tcx>>> Encodable<EncodeContext<'a, 'tcx>>
-    for Lazy<T>
-{
-    fn encode(&self, e: &mut EncodeContext<'a, 'tcx>) -> opaque::EncodeResult {
-        e.emit_lazy_distance(*self)
+impl<'a, 'tcx, T> Encodable<EncodeContext<'a, 'tcx>> for LazyValue<T> {
+    fn encode(&self, e: &mut EncodeContext<'a, 'tcx>) {
+        e.emit_lazy_distance(self.position);
     }
 }
 
-impl<'a, 'tcx, T: Encodable<EncodeContext<'a, 'tcx>>> Encodable<EncodeContext<'a, 'tcx>>
-    for Lazy<[T]>
-{
-    fn encode(&self, e: &mut EncodeContext<'a, 'tcx>) -> opaque::EncodeResult {
-        e.emit_usize(self.meta)?;
-        if self.meta == 0 {
-            return Ok(());
+impl<'a, 'tcx, T> Encodable<EncodeContext<'a, 'tcx>> for LazyArray<T> {
+    fn encode(&self, e: &mut EncodeContext<'a, 'tcx>) {
+        e.emit_usize(self.num_elems);
+        if self.num_elems > 0 {
+            e.emit_lazy_distance(self.position)
         }
-        e.emit_lazy_distance(*self)
     }
 }
 
-impl<'a, 'tcx, I: Idx, T> Encodable<EncodeContext<'a, 'tcx>> for Lazy<Table<I, T>>
-where
-    Option<T>: FixedSizeEncoding,
-{
-    fn encode(&self, e: &mut EncodeContext<'a, 'tcx>) -> opaque::EncodeResult {
-        e.emit_usize(self.meta)?;
-        e.emit_lazy_distance(*self)
+impl<'a, 'tcx, I, T> Encodable<EncodeContext<'a, 'tcx>> for LazyTable<I, T> {
+    fn encode(&self, e: &mut EncodeContext<'a, 'tcx>) {
+        e.emit_usize(self.encoded_size);
+        e.emit_lazy_distance(self.position);
     }
 }
 
 impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for CrateNum {
-    fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) -> opaque::EncodeResult {
+    fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) {
         if *self != LOCAL_CRATE && s.is_proc_macro {
             panic!("Attempted to encode non-local CrateNum {:?} for proc-macro crate", self);
         }
-        s.emit_u32(self.as_u32())
+        s.emit_u32(self.as_u32());
     }
 }
 
 impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for DefIndex {
-    fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) -> opaque::EncodeResult {
-        s.emit_u32(self.as_u32())
+    fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) {
+        s.emit_u32(self.as_u32());
     }
 }
 
 impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for ExpnIndex {
-    fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) -> opaque::EncodeResult {
-        s.emit_u32(self.as_u32())
+    fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) {
+        s.emit_u32(self.as_u32());
     }
 }
 
 impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for SyntaxContext {
-    fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) -> opaque::EncodeResult {
-        rustc_span::hygiene::raw_encode_syntax_context(*self, &s.hygiene_ctxt, s)
+    fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) {
+        rustc_span::hygiene::raw_encode_syntax_context(*self, &s.hygiene_ctxt, s);
     }
 }
 
 impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for ExpnId {
-    fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) -> opaque::EncodeResult {
+    fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) {
         if self.krate == LOCAL_CRATE {
             // We will only write details for local expansions.  Non-local expansions will fetch
             // data from the corresponding crate's metadata.
@@ -196,13 +176,13 @@
             // metadata from proc-macro crates.
             s.hygiene_ctxt.schedule_expn_data_for_encoding(*self);
         }
-        self.krate.encode(s)?;
-        self.local_id.encode(s)
+        self.krate.encode(s);
+        self.local_id.encode(s);
     }
 }
 
 impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for Span {
-    fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) -> opaque::EncodeResult {
+    fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) {
         let span = self.data();
 
         // Don't serialize any `SyntaxContext`s from a proc-macro crate,
@@ -237,9 +217,9 @@
         // `rustc_span::hygiene::raw_encode_expn_id` to handle
         // encoding `ExpnData` for proc-macro crates.
         if s.is_proc_macro {
-            SyntaxContext::root().encode(s)?;
+            SyntaxContext::root().encode(s);
         } else {
-            span.ctxt.encode(s)?;
+            span.ctxt.encode(s);
         }
 
         if self.is_dummy() {
@@ -307,28 +287,28 @@
             (TAG_VALID_SPAN_LOCAL, span.lo, span.hi)
         };
 
-        tag.encode(s)?;
-        lo.encode(s)?;
+        tag.encode(s);
+        lo.encode(s);
 
         // Encode length which is usually less than span.hi and profits more
         // from the variable-length integer encoding that we use.
         let len = hi - lo;
-        len.encode(s)?;
+        len.encode(s);
 
         if tag == TAG_VALID_SPAN_FOREIGN {
             // This needs to be two lines to avoid holding the `s.source_file_cache`
             // while calling `cnum.encode(s)`
             let cnum = s.source_file_cache.0.cnum;
-            cnum.encode(s)?;
+            cnum.encode(s);
         }
-
-        Ok(())
     }
 }
 
-impl<'a, 'tcx> TyEncoder<'tcx> for EncodeContext<'a, 'tcx> {
+impl<'a, 'tcx> TyEncoder for EncodeContext<'a, 'tcx> {
     const CLEAR_CROSS_CRATE: bool = true;
 
+    type I = TyCtxt<'tcx>;
+
     fn position(&self) -> usize {
         self.opaque.position()
     }
@@ -341,56 +321,14 @@
         &mut self.predicate_shorthands
     }
 
-    fn encode_alloc_id(
-        &mut self,
-        alloc_id: &rustc_middle::mir::interpret::AllocId,
-    ) -> Result<(), Self::Error> {
+    fn encode_alloc_id(&mut self, alloc_id: &rustc_middle::mir::interpret::AllocId) {
         let (index, _) = self.interpret_allocs.insert_full(*alloc_id);
 
-        index.encode(self)
+        index.encode(self);
     }
 }
 
-impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for &'tcx [thir::abstract_const::Node<'tcx>] {
-    fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) -> opaque::EncodeResult {
-        (**self).encode(s)
-    }
-}
-
-impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for &'tcx [(ty::Predicate<'tcx>, Span)] {
-    fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) -> opaque::EncodeResult {
-        (**self).encode(s)
-    }
-}
-
-/// Helper trait to allow overloading `EncodeContext::lazy` for iterators.
-trait EncodeContentsForLazy<'a, 'tcx, T: ?Sized + LazyMeta> {
-    fn encode_contents_for_lazy(self, ecx: &mut EncodeContext<'a, 'tcx>) -> T::Meta;
-}
-
-impl<'a, 'tcx, T: Encodable<EncodeContext<'a, 'tcx>>> EncodeContentsForLazy<'a, 'tcx, T> for &T {
-    fn encode_contents_for_lazy(self, ecx: &mut EncodeContext<'a, 'tcx>) {
-        self.encode(ecx).unwrap()
-    }
-}
-
-impl<'a, 'tcx, T: Encodable<EncodeContext<'a, 'tcx>>> EncodeContentsForLazy<'a, 'tcx, T> for T {
-    fn encode_contents_for_lazy(self, ecx: &mut EncodeContext<'a, 'tcx>) {
-        self.encode(ecx).unwrap()
-    }
-}
-
-impl<'a, 'tcx, I, T: Encodable<EncodeContext<'a, 'tcx>>> EncodeContentsForLazy<'a, 'tcx, [T]> for I
-where
-    I: IntoIterator,
-    I::Item: EncodeContentsForLazy<'a, 'tcx, T>,
-{
-    fn encode_contents_for_lazy(self, ecx: &mut EncodeContext<'a, 'tcx>) -> usize {
-        self.into_iter().map(|value| value.encode_contents_for_lazy(ecx)).count()
-    }
-}
-
-// Shorthand for `$self.$tables.$table.set($def_id.index, $self.lazy($value))`, which would
+// Shorthand for `$self.$tables.$table.set($def_id.index, $self.lazy_value($value))`, which would
 // normally need extra variables to avoid errors about multiple mutable borrows.
 macro_rules! record {
     ($self:ident.$tables:ident.$table:ident[$def_id:expr] <- $value:expr) => {{
@@ -402,12 +340,21 @@
     }};
 }
 
+// Shorthand for `$self.$tables.$table.set($def_id.index, $self.lazy_value($value))`, which would
+// normally need extra variables to avoid errors about multiple mutable borrows.
+macro_rules! record_array {
+    ($self:ident.$tables:ident.$table:ident[$def_id:expr] <- $value:expr) => {{
+        {
+            let value = $value;
+            let lazy = $self.lazy_array(value);
+            $self.$tables.$table.set($def_id.index, lazy);
+        }
+    }};
+}
+
 impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
-    fn emit_lazy_distance<T: ?Sized + LazyMeta>(
-        &mut self,
-        lazy: Lazy<T>,
-    ) -> Result<(), <Self as Encoder>::Error> {
-        let pos = lazy.position.get();
+    fn emit_lazy_distance(&mut self, position: NonZeroUsize) {
+        let pos = position.get();
         let distance = match self.lazy_state {
             LazyState::NoNode => bug!("emit_lazy_distance: outside of a metadata node"),
             LazyState::NodeStart(start) => {
@@ -417,31 +364,50 @@
             }
             LazyState::Previous(last_pos) => {
                 assert!(
-                    last_pos <= lazy.position,
+                    last_pos <= position,
                     "make sure that the calls to `lazy*` \
                      are in the same order as the metadata fields",
                 );
-                lazy.position.get() - last_pos.get()
+                position.get() - last_pos.get()
             }
         };
         self.lazy_state = LazyState::Previous(NonZeroUsize::new(pos).unwrap());
-        self.emit_usize(distance)
+        self.emit_usize(distance);
     }
 
-    fn lazy<T: ?Sized + LazyMeta>(
-        &mut self,
-        value: impl EncodeContentsForLazy<'a, 'tcx, T>,
-    ) -> Lazy<T> {
+    fn lazy<T: ParameterizedOverTcx, B: Borrow<T::Value<'tcx>>>(&mut self, value: B) -> LazyValue<T>
+    where
+        T::Value<'tcx>: Encodable<EncodeContext<'a, 'tcx>>,
+    {
         let pos = NonZeroUsize::new(self.position()).unwrap();
 
         assert_eq!(self.lazy_state, LazyState::NoNode);
         self.lazy_state = LazyState::NodeStart(pos);
-        let meta = value.encode_contents_for_lazy(self);
+        value.borrow().encode(self);
         self.lazy_state = LazyState::NoNode;
 
         assert!(pos.get() <= self.position());
 
-        Lazy::from_position_and_meta(pos, meta)
+        LazyValue::from_position(pos)
+    }
+
+    fn lazy_array<T: ParameterizedOverTcx, I: IntoIterator<Item = B>, B: Borrow<T::Value<'tcx>>>(
+        &mut self,
+        values: I,
+    ) -> LazyArray<T>
+    where
+        T::Value<'tcx>: Encodable<EncodeContext<'a, 'tcx>>,
+    {
+        let pos = NonZeroUsize::new(self.position()).unwrap();
+
+        assert_eq!(self.lazy_state, LazyState::NoNode);
+        self.lazy_state = LazyState::NodeStart(pos);
+        let len = values.into_iter().map(|value| value.borrow().encode(self)).count();
+        self.lazy_state = LazyState::NoNode;
+
+        assert!(pos.get() <= self.position());
+
+        LazyArray::from_position_and_num_elems(pos, len)
     }
 
     fn encode_info_for_items(&mut self) {
@@ -453,11 +419,11 @@
             return;
         }
 
-        self.tcx.hir().visit_all_item_likes(&mut self.as_deep_visitor());
+        self.tcx.hir().deep_visit_all_item_likes(self);
     }
 
     fn encode_def_path_table(&mut self) {
-        let table = self.tcx.resolutions(()).definitions.def_path_table();
+        let table = self.tcx.definitions_untracked().def_path_table();
         if self.is_proc_macro {
             for def_index in std::iter::once(CRATE_DEF_INDEX)
                 .chain(self.tcx.resolutions(()).proc_macros.iter().map(|p| p.local_def_index))
@@ -476,13 +442,13 @@
         }
     }
 
-    fn encode_def_path_hash_map(&mut self) -> Lazy<DefPathHashMapRef<'tcx>> {
+    fn encode_def_path_hash_map(&mut self) -> LazyValue<DefPathHashMapRef<'static>> {
         self.lazy(DefPathHashMapRef::BorrowedFromTcx(
-            self.tcx.resolutions(()).definitions.def_path_hash_to_def_index_map(),
+            self.tcx.definitions_untracked().def_path_hash_to_def_index_map(),
         ))
     }
 
-    fn encode_source_map(&mut self) -> Lazy<[rustc_span::SourceFile]> {
+    fn encode_source_map(&mut self) -> LazyArray<rustc_span::SourceFile> {
         let source_map = self.tcx.sess.source_map();
         let all_source_files = source_map.files();
 
@@ -491,6 +457,8 @@
         // is done.
         let required_source_files = self.required_source_files.take().unwrap();
 
+        let working_directory = &self.tcx.sess.opts.working_dir;
+
         let adapted = all_source_files
             .iter()
             .enumerate()
@@ -503,66 +471,40 @@
                 (!source_file.is_imported() || self.is_proc_macro)
             })
             .map(|(_, source_file)| {
-                let mut adapted = match source_file.name {
-                    FileName::Real(ref realname) => {
-                        let mut adapted = (**source_file).clone();
-                        adapted.name = FileName::Real(match realname {
-                            RealFileName::LocalPath(path_to_file) => {
-                                // Prepend path of working directory onto potentially
-                                // relative paths, because they could become relative
-                                // to a wrong directory.
-                                // We include `working_dir` as part of the crate hash,
-                                // so it's okay for us to use it as part of the encoded
-                                // metadata.
-                                let working_dir = &self.tcx.sess.opts.working_dir;
-                                match working_dir {
-                                    RealFileName::LocalPath(absolute) => {
-                                        // Although neither working_dir or the file name were subject
-                                        // to path remapping, the concatenation between the two may
-                                        // be. Hence we need to do a remapping here.
-                                        let joined = Path::new(absolute).join(path_to_file);
-                                        let (joined, remapped) =
-                                            source_map.path_mapping().map_prefix(joined);
-                                        if remapped {
-                                            RealFileName::Remapped {
-                                                local_path: None,
-                                                virtual_name: joined,
-                                            }
-                                        } else {
-                                            RealFileName::LocalPath(joined)
-                                        }
-                                    }
-                                    RealFileName::Remapped { local_path: _, virtual_name } => {
-                                        // If working_dir has been remapped, then we emit
-                                        // Remapped variant as the expanded path won't be valid
-                                        RealFileName::Remapped {
-                                            local_path: None,
-                                            virtual_name: Path::new(virtual_name)
-                                                .join(path_to_file),
-                                        }
-                                    }
-                                }
-                            }
-                            RealFileName::Remapped { local_path: _, virtual_name } => {
-                                RealFileName::Remapped {
-                                    // We do not want any local path to be exported into metadata
-                                    local_path: None,
-                                    virtual_name: virtual_name.clone(),
-                                }
-                            }
-                        });
-                        adapted.name_hash = {
-                            let mut hasher: StableHasher = StableHasher::new();
-                            adapted.name.hash(&mut hasher);
-                            hasher.finish::<u128>()
-                        };
-                        Lrc::new(adapted)
-                    }
+                // At export time we expand all source file paths to absolute paths because
+                // downstream compilation sessions can have a different compiler working
+                // directory, so relative paths from this or any other upstream crate
+                // won't be valid anymore.
+                //
+                // At this point we also erase the actual on-disk path and only keep
+                // the remapped version -- as is necessary for reproducible builds.
+                match source_file.name {
+                    FileName::Real(ref original_file_name) => {
+                        let adapted_file_name =
+                            source_map.path_mapping().to_embeddable_absolute_path(
+                                original_file_name.clone(),
+                                working_directory,
+                            );
 
+                        if adapted_file_name != *original_file_name {
+                            let mut adapted: SourceFile = (**source_file).clone();
+                            adapted.name = FileName::Real(adapted_file_name);
+                            adapted.name_hash = {
+                                let mut hasher: StableHasher = StableHasher::new();
+                                adapted.name.hash(&mut hasher);
+                                hasher.finish::<u128>()
+                            };
+                            Lrc::new(adapted)
+                        } else {
+                            // Nothing to adapt
+                            source_file.clone()
+                        }
+                    }
                     // expanded code, not from a file
                     _ => source_file.clone(),
-                };
-
+                }
+            })
+            .map(|mut source_file| {
                 // We're serializing this `SourceFile` into our crate metadata,
                 // so mark it as coming from this crate.
                 // This also ensures that we don't try to deserialize the
@@ -570,20 +512,22 @@
                 // dependencies aren't loaded when we deserialize a proc-macro,
                 // trying to remap the `CrateNum` would fail.
                 if self.is_proc_macro {
-                    Lrc::make_mut(&mut adapted).cnum = LOCAL_CRATE;
+                    Lrc::make_mut(&mut source_file).cnum = LOCAL_CRATE;
                 }
-                adapted
+                source_file
             })
             .collect::<Vec<_>>();
 
-        self.lazy(adapted.iter().map(|rc| &**rc))
+        self.lazy_array(adapted.iter().map(|rc| &**rc))
     }
 
-    fn encode_crate_root(&mut self) -> Lazy<CrateRoot<'tcx>> {
+    fn encode_crate_root(&mut self) -> LazyValue<CrateRoot> {
         let tcx = self.tcx;
-        let mut i = self.position();
+        let mut i = 0;
+        let preamble_bytes = self.position() - i;
 
         // Encode the crate deps
+        i = self.position();
         let crate_deps = self.encode_crate_deps();
         let dylib_dependency_formats = self.encode_dylib_dependency_formats();
         let dep_bytes = self.position() - i;
@@ -609,7 +553,9 @@
         let native_libraries = self.encode_native_libraries();
         let native_lib_bytes = self.position() - i;
 
+        i = self.position();
         let foreign_modules = self.encode_foreign_modules();
+        let foreign_modules_bytes = self.position() - i;
 
         // Encode DefPathTable
         i = self.position();
@@ -629,6 +575,7 @@
         i = self.position();
         let incoherent_impls = self.encode_incoherent_impls();
         let incoherent_impls_bytes = self.position() - i;
+
         // Encode MIR.
         i = self.position();
         self.encode_mir();
@@ -641,6 +588,7 @@
         let item_bytes = self.position() - i;
 
         // Encode the allocation index
+        i = self.position();
         let interpret_alloc_index = {
             let mut interpret_alloc_index = Vec::new();
             let mut n = 0;
@@ -657,12 +605,13 @@
                     let id = self.interpret_allocs[idx];
                     let pos = self.position() as u32;
                     interpret_alloc_index.push(pos);
-                    interpret::specialized_encode_alloc_id(self, tcx, id).unwrap();
+                    interpret::specialized_encode_alloc_id(self, tcx, id);
                 }
                 n = new_n;
             }
-            self.lazy(interpret_alloc_index)
+            self.lazy_array(interpret_alloc_index)
         };
+        let interpret_alloc_index_bytes = self.position() - i;
 
         // Encode the proc macro data. This affects 'tables',
         // so we need to do this before we encode the tables
@@ -707,9 +656,9 @@
         let source_map = self.encode_source_map();
         let source_map_bytes = self.position() - i;
 
+        i = self.position();
         let attrs = tcx.hir().krate_attrs();
         let has_default_lib_allocator = tcx.sess.contains_name(&attrs, sym::default_lib_allocator);
-
         let root = self.lazy(CrateRoot {
             name: tcx.crate_name(LOCAL_CRATE),
             extra_filename: tcx.sess.opts.cg.extra_filename.clone(),
@@ -752,9 +701,34 @@
             expn_hashes,
             def_path_hash_map,
         });
+        let final_bytes = self.position() - i;
 
         let total_bytes = self.position();
 
+        let computed_total_bytes = preamble_bytes
+            + dep_bytes
+            + lib_feature_bytes
+            + lang_item_bytes
+            + diagnostic_item_bytes
+            + native_lib_bytes
+            + foreign_modules_bytes
+            + def_path_table_bytes
+            + traits_bytes
+            + impls_bytes
+            + incoherent_impls_bytes
+            + mir_bytes
+            + item_bytes
+            + interpret_alloc_index_bytes
+            + proc_macro_data_bytes
+            + tables_bytes
+            + debugger_visualizers_bytes
+            + exported_symbols_bytes
+            + hygiene_bytes
+            + def_path_hash_map_bytes
+            + source_map_bytes
+            + final_bytes;
+        assert_eq!(total_bytes, computed_total_bytes);
+
         if tcx.sess.meta_stats() {
             let mut zero_bytes = 0;
             for e in self.opaque.data.iter() {
@@ -763,27 +737,41 @@
                 }
             }
 
-            eprintln!("metadata stats:");
-            eprintln!("                  dep bytes: {}", dep_bytes);
-            eprintln!("          lib feature bytes: {}", lib_feature_bytes);
-            eprintln!("            lang item bytes: {}", lang_item_bytes);
-            eprintln!("      diagnostic item bytes: {}", diagnostic_item_bytes);
-            eprintln!("               native bytes: {}", native_lib_bytes);
-            eprintln!(" debugger visualizers bytes: {}", debugger_visualizers_bytes);
-            eprintln!("           source_map bytes: {}", source_map_bytes);
-            eprintln!("               traits bytes: {}", traits_bytes);
-            eprintln!("                impls bytes: {}", impls_bytes);
-            eprintln!("     incoherent_impls bytes: {}", incoherent_impls_bytes);
-            eprintln!("         exp. symbols bytes: {}", exported_symbols_bytes);
-            eprintln!("       def-path table bytes: {}", def_path_table_bytes);
-            eprintln!("      def-path hashes bytes: {}", def_path_hash_map_bytes);
-            eprintln!("      proc-macro-data-bytes: {}", proc_macro_data_bytes);
-            eprintln!("                  mir bytes: {}", mir_bytes);
-            eprintln!("                 item bytes: {}", item_bytes);
-            eprintln!("                table bytes: {}", tables_bytes);
-            eprintln!("              hygiene bytes: {}", hygiene_bytes);
-            eprintln!("                 zero bytes: {}", zero_bytes);
-            eprintln!("                total bytes: {}", total_bytes);
+            let perc = |bytes| (bytes * 100) as f64 / total_bytes as f64;
+            let p = |label, bytes| {
+                eprintln!("{:>21}: {:>8} bytes ({:4.1}%)", label, bytes, perc(bytes));
+            };
+
+            eprintln!("");
+            eprintln!(
+                "{} metadata bytes, of which {} bytes ({:.1}%) are zero",
+                total_bytes,
+                zero_bytes,
+                perc(zero_bytes)
+            );
+            p("preamble", preamble_bytes);
+            p("dep", dep_bytes);
+            p("lib feature", lib_feature_bytes);
+            p("lang item", lang_item_bytes);
+            p("diagnostic item", diagnostic_item_bytes);
+            p("native lib", native_lib_bytes);
+            p("foreign modules", foreign_modules_bytes);
+            p("def-path table", def_path_table_bytes);
+            p("traits", traits_bytes);
+            p("impls", impls_bytes);
+            p("incoherent_impls", incoherent_impls_bytes);
+            p("mir", mir_bytes);
+            p("item", item_bytes);
+            p("interpret_alloc_index", interpret_alloc_index_bytes);
+            p("proc-macro-data", proc_macro_data_bytes);
+            p("tables", tables_bytes);
+            p("debugger visualizers", debugger_visualizers_bytes);
+            p("exported symbols", exported_symbols_bytes);
+            p("hygiene", hygiene_bytes);
+            p("def-path hashes", def_path_hash_map_bytes);
+            p("source_map", source_map_bytes);
+            p("final", final_bytes);
+            eprintln!("");
         }
 
         root
@@ -890,9 +878,9 @@
             let needs_inline = (generics.requires_monomorphization(tcx)
                 || tcx.codegen_fn_attrs(def_id).requests_inline())
                 && tcx.sess.opts.output_types.should_codegen();
-            // The function has a `const` modifier or is annotated with `default_method_body_is_const`.
+            // The function has a `const` modifier or is in a `#[const_trait]`.
             let is_const_fn = tcx.is_const_fn_raw(def_id.to_def_id())
-                || tcx.has_attr(def_id.to_def_id(), sym::default_method_body_is_const);
+                || tcx.is_const_default_method(def_id.to_def_id());
             let always_encode_mir = tcx.sess.opts.debugging_opts.always_encode_mir;
             (is_const_fn, needs_inline || always_encode_mir)
         }
@@ -993,7 +981,7 @@
             .iter()
             .filter(|attr| !rustc_feature::is_builtin_only_local(attr.name_or_empty()));
 
-        record!(self.tables.attributes[def_id.to_def_id()] <- attrs.clone());
+        record_array!(self.tables.attributes[def_id.to_def_id()] <- attrs.clone());
         if attrs.any(|attr| attr.may_have_doc_links()) {
             self.tables.may_have_doc_links.set(def_id.local_def_index, ());
         }
@@ -1013,6 +1001,9 @@
             record!(self.tables.def_span[def_id] <- tcx.def_span(def_id));
             self.encode_attrs(local_id);
             record!(self.tables.expn_that_defined[def_id] <- self.tcx.expn_that_defined(def_id));
+            if let Some(ident_span) = tcx.def_ident_span(def_id) {
+                record!(self.tables.def_ident_span[def_id] <- ident_span);
+            }
             if def_kind.has_codegen_attrs() {
                 record!(self.tables.codegen_fn_attrs[def_id] <- self.tcx.codegen_fn_attrs(def_id));
             }
@@ -1026,7 +1017,7 @@
             }
             if should_encode_variances(def_kind) {
                 let v = self.tcx.variances_of(def_id);
-                record!(self.tables.variances_of[def_id] <- v);
+                record_array!(self.tables.variances_of[def_id] <- v);
             }
             if should_encode_generics(def_kind) {
                 let g = tcx.generics_of(def_id);
@@ -1034,7 +1025,7 @@
                 record!(self.tables.explicit_predicates_of[def_id] <- self.tcx.explicit_predicates_of(def_id));
                 let inferred_outlives = self.tcx.inferred_outlives_of(def_id);
                 if !inferred_outlives.is_empty() {
-                    record!(self.tables.inferred_outlives_of[def_id] <- inferred_outlives);
+                    record_array!(self.tables.inferred_outlives_of[def_id] <- inferred_outlives);
                 }
             }
             if let DefKind::Trait | DefKind::TraitAlias = def_kind {
@@ -1046,7 +1037,7 @@
             if implementations.is_empty() {
                 continue;
             }
-            record!(self.tables.inherent_impls[def_id.to_def_id()] <- implementations.iter().map(|&def_id| {
+            record_array!(self.tables.inherent_impls[def_id.to_def_id()] <- implementations.iter().map(|&def_id| {
                 assert!(def_id.is_local());
                 def_id.index
             }));
@@ -1072,12 +1063,11 @@
         };
 
         record!(self.tables.kind[def_id] <- EntryKind::Variant(self.lazy(data)));
-        self.tables.impl_constness.set(def_id.index, hir::Constness::Const);
-        record!(self.tables.children[def_id] <- variant.fields.iter().map(|f| {
+        self.tables.constness.set(def_id.index, hir::Constness::Const);
+        record_array!(self.tables.children[def_id] <- variant.fields.iter().map(|f| {
             assert!(f.did.is_local());
             f.did.index
         }));
-        self.encode_ident_span(def_id, variant.ident(tcx));
         self.encode_item_type(def_id);
         if variant.ctor_kind == CtorKind::Fn {
             // FIXME(eddyb) encode signature only in `encode_enum_variant_ctor`.
@@ -1102,7 +1092,7 @@
         };
 
         record!(self.tables.kind[def_id] <- EntryKind::Variant(self.lazy(data)));
-        self.tables.impl_constness.set(def_id.index, hir::Constness::Const);
+        self.tables.constness.set(def_id.index, hir::Constness::Const);
         self.encode_item_type(def_id);
         if variant.ctor_kind == CtorKind::Fn {
             record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id));
@@ -1121,11 +1111,11 @@
         // items - we encode information about proc-macros later on.
         let reexports = if !self.is_proc_macro {
             match tcx.module_reexports(local_def_id) {
-                Some(exports) => self.lazy(exports),
-                _ => Lazy::empty(),
+                Some(exports) => self.lazy_array(exports),
+                _ => LazyArray::empty(),
             }
         } else {
-            Lazy::empty()
+            LazyArray::empty()
         };
 
         record!(self.tables.kind[def_id] <- EntryKind::Mod(reexports));
@@ -1133,7 +1123,7 @@
             // Encode this here because we don't do it in encode_def_ids.
             record!(self.tables.expn_that_defined[def_id] <- tcx.expn_that_defined(local_def_id));
         } else {
-            record!(self.tables.children[def_id] <- iter_from_generator(|| {
+            record_array!(self.tables.children[def_id] <- iter::from_generator(|| {
                 for item_id in md.item_ids {
                     match tcx.hir().item(*item_id).kind {
                         // Foreign items are planted into their parent modules
@@ -1169,7 +1159,6 @@
         debug!("EncodeContext::encode_field({:?})", def_id);
 
         record!(self.tables.kind[def_id] <- EntryKind::Field);
-        self.encode_ident_span(def_id, field.ident(self.tcx));
         self.encode_item_type(def_id);
     }
 
@@ -1186,7 +1175,7 @@
         };
 
         record!(self.tables.repr_options[def_id] <- adt_def.repr());
-        self.tables.impl_constness.set(def_id.index, hir::Constness::Const);
+        self.tables.constness.set(def_id.index, hir::Constness::Const);
         record!(self.tables.kind[def_id] <- EntryKind::Struct(self.lazy(data)));
         self.encode_item_type(def_id);
         if variant.ctor_kind == CtorKind::Fn {
@@ -1198,7 +1187,7 @@
         debug!("EncodeContext::encode_explicit_item_bounds({:?})", def_id);
         let bounds = self.tcx.explicit_item_bounds(def_id);
         if !bounds.is_empty() {
-            record!(self.tables.explicit_item_bounds[def_id] <- bounds);
+            record_array!(self.tables.explicit_item_bounds[def_id] <- bounds);
         }
     }
 
@@ -1230,14 +1219,14 @@
                 let hir::TraitItemKind::Fn(m_sig, m) = &ast_item.kind else { bug!() };
                 match *m {
                     hir::TraitFn::Required(ref names) => {
-                        record!(self.tables.fn_arg_names[def_id] <- *names)
+                        record_array!(self.tables.fn_arg_names[def_id] <- *names)
                     }
                     hir::TraitFn::Provided(body) => {
-                        record!(self.tables.fn_arg_names[def_id] <- self.tcx.hir().body_param_names(body))
+                        record_array!(self.tables.fn_arg_names[def_id] <- self.tcx.hir().body_param_names(body))
                     }
                 };
                 self.tables.asyncness.set(def_id.index, m_sig.header.asyncness);
-                self.tables.impl_constness.set(def_id.index, hir::Constness::NotConst);
+                self.tables.constness.set(def_id.index, hir::Constness::NotConst);
                 record!(self.tables.kind[def_id] <- EntryKind::AssocFn(self.lazy(AssocFnData {
                     container,
                     has_self: trait_item.fn_has_self_parameter,
@@ -1248,7 +1237,6 @@
                 record!(self.tables.kind[def_id] <- EntryKind::AssocType(container));
             }
         }
-        self.encode_ident_span(def_id, ast_item.ident);
         match trait_item.kind {
             ty::AssocKind::Const | ty::AssocKind::Fn => {
                 self.encode_item_type(def_id);
@@ -1295,14 +1283,14 @@
             ty::AssocKind::Fn => {
                 let hir::ImplItemKind::Fn(ref sig, body) = ast_item.kind else { bug!() };
                 self.tables.asyncness.set(def_id.index, sig.header.asyncness);
-                record!(self.tables.fn_arg_names[def_id] <- self.tcx.hir().body_param_names(body));
+                record_array!(self.tables.fn_arg_names[def_id] <- self.tcx.hir().body_param_names(body));
                 // Can be inside `impl const Trait`, so using sig.header.constness is not reliable
                 let constness = if self.tcx.is_const_fn_raw(def_id) {
                     hir::Constness::Const
                 } else {
                     hir::Constness::NotConst
                 };
-                self.tables.impl_constness.set(def_id.index, constness);
+                self.tables.constness.set(def_id.index, constness);
                 record!(self.tables.kind[def_id] <- EntryKind::AssocFn(self.lazy(AssocFnData {
                     container,
                     has_self: impl_item.fn_has_self_parameter,
@@ -1312,13 +1300,15 @@
                 record!(self.tables.kind[def_id] <- EntryKind::AssocType(container));
             }
         }
-        self.encode_ident_span(def_id, impl_item.ident(self.tcx));
         self.encode_item_type(def_id);
         if let Some(trait_item_def_id) = impl_item.trait_item_def_id {
             self.tables.trait_item_def_id.set(def_id.index, trait_item_def_id.into());
         }
         if impl_item.kind == ty::AssocKind::Fn {
             record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id));
+            if tcx.is_intrinsic(def_id) {
+                self.tables.is_intrinsic.set(def_id.index, ());
+            }
         }
     }
 
@@ -1411,8 +1401,6 @@
 
         debug!("EncodeContext::encode_info_for_item({:?})", def_id);
 
-        self.encode_ident_span(def_id, item.ident);
-
         let entry_kind = match item.kind {
             hir::ItemKind::Static(..) => EntryKind::Static,
             hir::ItemKind::Const(_, body_id) => {
@@ -1424,8 +1412,8 @@
             }
             hir::ItemKind::Fn(ref sig, .., body) => {
                 self.tables.asyncness.set(def_id.index, sig.header.asyncness);
-                record!(self.tables.fn_arg_names[def_id] <- self.tcx.hir().body_param_names(body));
-                self.tables.impl_constness.set(def_id.index, sig.header.constness);
+                record_array!(self.tables.fn_arg_names[def_id] <- self.tcx.hir().body_param_names(body));
+                self.tables.constness.set(def_id.index, sig.header.constness);
                 EntryKind::Fn
             }
             hir::ItemKind::Macro(ref macro_def, _) => {
@@ -1449,7 +1437,7 @@
             hir::ItemKind::Struct(ref struct_def, _) => {
                 let adt_def = self.tcx.adt_def(def_id);
                 record!(self.tables.repr_options[def_id] <- adt_def.repr());
-                self.tables.impl_constness.set(def_id.index, hir::Constness::Const);
+                self.tables.constness.set(def_id.index, hir::Constness::Const);
 
                 // Encode def_ids for each field and method
                 // for methods, write all the stuff get_trait_method
@@ -1480,7 +1468,7 @@
             }
             hir::ItemKind::Impl(hir::Impl { defaultness, constness, .. }) => {
                 self.tables.impl_defaultness.set(def_id.index, *defaultness);
-                self.tables.impl_constness.set(def_id.index, *constness);
+                self.tables.constness.set(def_id.index, *constness);
 
                 let trait_ref = self.tcx.impl_trait_ref(def_id);
                 if let Some(trait_ref) = trait_ref {
@@ -1524,14 +1512,14 @@
         record!(self.tables.kind[def_id] <- entry_kind);
         // FIXME(eddyb) there should be a nicer way to do this.
         match item.kind {
-            hir::ItemKind::Enum(..) => record!(self.tables.children[def_id] <-
+            hir::ItemKind::Enum(..) => record_array!(self.tables.children[def_id] <-
                 self.tcx.adt_def(def_id).variants().iter().map(|v| {
                     assert!(v.def_id.is_local());
                     v.def_id.index
                 })
             ),
             hir::ItemKind::Struct(..) | hir::ItemKind::Union(..) => {
-                record!(self.tables.children[def_id] <-
+                record_array!(self.tables.children[def_id] <-
                     self.tcx.adt_def(def_id).non_enum_variant().fields.iter().map(|f| {
                         assert!(f.did.is_local());
                         f.did.index
@@ -1540,7 +1528,7 @@
             }
             hir::ItemKind::Impl { .. } | hir::ItemKind::Trait(..) => {
                 let associated_item_def_ids = self.tcx.associated_item_def_ids(def_id);
-                record!(self.tables.children[def_id] <-
+                record_array!(self.tables.children[def_id] <-
                     associated_item_def_ids.iter().map(|&def_id| {
                         assert!(def_id.is_local());
                         def_id.index
@@ -1563,6 +1551,9 @@
         }
         if let hir::ItemKind::Fn(..) = item.kind {
             record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id));
+            if tcx.is_intrinsic(def_id) {
+                self.tables.is_intrinsic.set(def_id.index, ());
+            }
         }
         if let hir::ItemKind::Impl { .. } = item.kind {
             if let Some(trait_ref) = self.tcx.impl_trait_ref(def_id) {
@@ -1619,16 +1610,16 @@
         self.encode_item_type(def_id.to_def_id());
     }
 
-    fn encode_native_libraries(&mut self) -> Lazy<[NativeLib]> {
+    fn encode_native_libraries(&mut self) -> LazyArray<NativeLib> {
         empty_proc_macro!(self);
         let used_libraries = self.tcx.native_libraries(LOCAL_CRATE);
-        self.lazy(used_libraries.iter())
+        self.lazy_array(used_libraries.iter())
     }
 
-    fn encode_foreign_modules(&mut self) -> Lazy<[ForeignModule]> {
+    fn encode_foreign_modules(&mut self) -> LazyArray<ForeignModule> {
         empty_proc_macro!(self);
         let foreign_modules = self.tcx.foreign_modules(LOCAL_CRATE);
-        self.lazy(foreign_modules.iter().map(|(_, m)| m).cloned())
+        self.lazy_array(foreign_modules.iter().map(|(_, m)| m).cloned())
     }
 
     fn encode_hygiene(&mut self) -> (SyntaxContextTable, ExpnDataTable, ExpnHashTable) {
@@ -1636,18 +1627,16 @@
         let mut expn_data_table: TableBuilder<_, _> = Default::default();
         let mut expn_hash_table: TableBuilder<_, _> = Default::default();
 
-        let _: Result<(), !> = self.hygiene_ctxt.encode(
+        self.hygiene_ctxt.encode(
             &mut (&mut *self, &mut syntax_contexts, &mut expn_data_table, &mut expn_hash_table),
             |(this, syntax_contexts, _, _), index, ctxt_data| {
                 syntax_contexts.set(index, this.lazy(ctxt_data));
-                Ok(())
             },
             |(this, _, expn_data_table, expn_hash_table), index, expn_data, hash| {
                 if let Some(index) = index.as_local() {
                     expn_data_table.set(index.as_raw(), this.lazy(expn_data));
                     expn_hash_table.set(index.as_raw(), this.lazy(hash));
                 }
-                Ok(())
             },
         );
 
@@ -1667,7 +1656,7 @@
             let proc_macro_decls_static = tcx.proc_macro_decls_static(()).unwrap().local_def_index;
             let stability = tcx.lookup_stability(CRATE_DEF_ID);
             let macros =
-                self.lazy(tcx.resolutions(()).proc_macros.iter().map(|p| p.local_def_index));
+                self.lazy_array(tcx.resolutions(()).proc_macros.iter().map(|p| p.local_def_index));
             let spans = self.tcx.sess.parse_sess.proc_macro_quoted_spans();
             for (i, span) in spans.into_iter().enumerate() {
                 let span = self.lazy(span);
@@ -1733,12 +1722,12 @@
         }
     }
 
-    fn encode_debugger_visualizers(&mut self) -> Lazy<[DebuggerVisualizerFile]> {
+    fn encode_debugger_visualizers(&mut self) -> LazyArray<DebuggerVisualizerFile> {
         empty_proc_macro!(self);
-        self.lazy(self.tcx.debugger_visualizers(LOCAL_CRATE).iter())
+        self.lazy_array(self.tcx.debugger_visualizers(LOCAL_CRATE).iter())
     }
 
-    fn encode_crate_deps(&mut self) -> Lazy<[CrateDep]> {
+    fn encode_crate_deps(&mut self) -> LazyArray<CrateDep> {
         empty_proc_macro!(self);
 
         let deps = self
@@ -1770,29 +1759,29 @@
         // the assumption that they are numbered 1 to n.
         // FIXME (#2166): This is not nearly enough to support correct versioning
         // but is enough to get transitive crate dependencies working.
-        self.lazy(deps.iter().map(|&(_, ref dep)| dep))
+        self.lazy_array(deps.iter().map(|&(_, ref dep)| dep))
     }
 
-    fn encode_lib_features(&mut self) -> Lazy<[(Symbol, Option<Symbol>)]> {
+    fn encode_lib_features(&mut self) -> LazyArray<(Symbol, Option<Symbol>)> {
         empty_proc_macro!(self);
         let tcx = self.tcx;
         let lib_features = tcx.lib_features(());
-        self.lazy(lib_features.to_vec())
+        self.lazy_array(lib_features.to_vec())
     }
 
-    fn encode_diagnostic_items(&mut self) -> Lazy<[(Symbol, DefIndex)]> {
+    fn encode_diagnostic_items(&mut self) -> LazyArray<(Symbol, DefIndex)> {
         empty_proc_macro!(self);
         let tcx = self.tcx;
         let diagnostic_items = &tcx.diagnostic_items(LOCAL_CRATE).name_to_id;
-        self.lazy(diagnostic_items.iter().map(|(&name, def_id)| (name, def_id.index)))
+        self.lazy_array(diagnostic_items.iter().map(|(&name, def_id)| (name, def_id.index)))
     }
 
-    fn encode_lang_items(&mut self) -> Lazy<[(DefIndex, usize)]> {
+    fn encode_lang_items(&mut self) -> LazyArray<(DefIndex, usize)> {
         empty_proc_macro!(self);
         let tcx = self.tcx;
         let lang_items = tcx.lang_items();
         let lang_items = lang_items.items().iter();
-        self.lazy(lang_items.enumerate().filter_map(|(i, &opt_def_id)| {
+        self.lazy_array(lang_items.enumerate().filter_map(|(i, &opt_def_id)| {
             if let Some(def_id) = opt_def_id {
                 if def_id.is_local() {
                     return Some((def_id.index, i));
@@ -1802,19 +1791,19 @@
         }))
     }
 
-    fn encode_lang_items_missing(&mut self) -> Lazy<[lang_items::LangItem]> {
+    fn encode_lang_items_missing(&mut self) -> LazyArray<lang_items::LangItem> {
         empty_proc_macro!(self);
         let tcx = self.tcx;
-        self.lazy(&tcx.lang_items().missing)
+        self.lazy_array(&tcx.lang_items().missing)
     }
 
-    fn encode_traits(&mut self) -> Lazy<[DefIndex]> {
+    fn encode_traits(&mut self) -> LazyArray<DefIndex> {
         empty_proc_macro!(self);
-        self.lazy(self.tcx.traits_in_crate(LOCAL_CRATE).iter().map(|def_id| def_id.index))
+        self.lazy_array(self.tcx.traits_in_crate(LOCAL_CRATE).iter().map(|def_id| def_id.index))
     }
 
     /// Encodes an index, mapping each trait to its (local) implementations.
-    fn encode_impls(&mut self) -> Lazy<[TraitImpls]> {
+    fn encode_impls(&mut self) -> LazyArray<TraitImpls> {
         debug!("EncodeContext::encode_traits_and_impls()");
         empty_proc_macro!(self);
         let tcx = self.tcx;
@@ -1827,7 +1816,7 @@
                     let simplified_self_ty = fast_reject::simplify_type(
                         self.tcx,
                         trait_ref.self_ty(),
-                        TreatParams::AsPlaceholders,
+                        TreatParams::AsInfer,
                     );
 
                     fx_hash_map
@@ -1853,15 +1842,15 @@
 
                 TraitImpls {
                     trait_id: (trait_def_id.krate.as_u32(), trait_def_id.index),
-                    impls: self.lazy(&impls),
+                    impls: self.lazy_array(&impls),
                 }
             })
             .collect();
 
-        self.lazy(&all_impls)
+        self.lazy_array(&all_impls)
     }
 
-    fn encode_incoherent_impls(&mut self) -> Lazy<[IncoherentImpls]> {
+    fn encode_incoherent_impls(&mut self) -> LazyArray<IncoherentImpls> {
         debug!("EncodeContext::encode_traits_and_impls()");
         empty_proc_macro!(self);
         let tcx = self.tcx;
@@ -1881,11 +1870,11 @@
                     tcx.hir().def_path_hash(LocalDefId { local_def_index })
                 });
 
-                IncoherentImpls { self_ty: simp, impls: self.lazy(impls) }
+                IncoherentImpls { self_ty: simp, impls: self.lazy_array(impls) }
             })
             .collect();
 
-        self.lazy(&all_impls)
+        self.lazy_array(&all_impls)
     }
 
     // Encodes all symbols exported from this crate into the metadata.
@@ -1897,13 +1886,13 @@
     fn encode_exported_symbols(
         &mut self,
         exported_symbols: &[(ExportedSymbol<'tcx>, SymbolExportInfo)],
-    ) -> Lazy<[(ExportedSymbol<'tcx>, SymbolExportInfo)]> {
+    ) -> LazyArray<(ExportedSymbol<'static>, SymbolExportInfo)> {
         empty_proc_macro!(self);
         // The metadata symbol name is special. It should not show up in
         // downstream crates.
         let metadata_symbol_name = SymbolName::new(self.tcx, &metadata_symbol_name(self.tcx));
 
-        self.lazy(
+        self.lazy_array(
             exported_symbols
                 .iter()
                 .filter(|&&(ref exported_symbol, _)| match *exported_symbol {
@@ -1914,21 +1903,21 @@
         )
     }
 
-    fn encode_dylib_dependency_formats(&mut self) -> Lazy<[Option<LinkagePreference>]> {
+    fn encode_dylib_dependency_formats(&mut self) -> LazyArray<Option<LinkagePreference>> {
         empty_proc_macro!(self);
         let formats = self.tcx.dependency_formats(());
         for (ty, arr) in formats.iter() {
             if *ty != CrateType::Dylib {
                 continue;
             }
-            return self.lazy(arr.iter().map(|slot| match *slot {
+            return self.lazy_array(arr.iter().map(|slot| match *slot {
                 Linkage::NotLinked | Linkage::IncludedFromDylib => None,
 
                 Linkage::Dynamic => Some(LinkagePreference::RequireDynamic),
                 Linkage::Static => Some(LinkagePreference::RequireStatic),
             }));
         }
-        Lazy::empty()
+        LazyArray::empty()
     }
 
     fn encode_info_for_foreign_item(&mut self, def_id: DefId, nitem: &hir::ForeignItem<'_>) {
@@ -1939,13 +1928,13 @@
         match nitem.kind {
             hir::ForeignItemKind::Fn(_, ref names, _) => {
                 self.tables.asyncness.set(def_id.index, hir::IsAsync::NotAsync);
-                record!(self.tables.fn_arg_names[def_id] <- *names);
+                record_array!(self.tables.fn_arg_names[def_id] <- *names);
                 let constness = if self.tcx.is_const_fn_raw(def_id) {
                     hir::Constness::Const
                 } else {
                     hir::Constness::NotConst
                 };
-                self.tables.impl_constness.set(def_id.index, constness);
+                self.tables.constness.set(def_id.index, constness);
                 record!(self.tables.kind[def_id] <- EntryKind::ForeignFn);
             }
             hir::ForeignItemKind::Static(..) => {
@@ -1955,10 +1944,12 @@
                 record!(self.tables.kind[def_id] <- EntryKind::ForeignType);
             }
         }
-        self.encode_ident_span(def_id, nitem.ident);
         self.encode_item_type(def_id);
         if let hir::ForeignItemKind::Fn(..) = nitem.kind {
             record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id));
+            if tcx.is_intrinsic(def_id) {
+                self.tables.is_intrinsic.set(def_id.index, ());
+            }
         }
     }
 }
@@ -2029,15 +2020,11 @@
     }
 
     fn encode_info_for_expr(&mut self, expr: &hir::Expr<'_>) {
-        if let hir::ExprKind::Closure(..) = expr.kind {
+        if let hir::ExprKind::Closure { .. } = expr.kind {
             self.encode_info_for_closure(expr.hir_id);
         }
     }
 
-    fn encode_ident_span(&mut self, def_id: DefId, ident: Ident) {
-        record!(self.tables.def_ident_span[def_id] <- ident.span);
-    }
-
     /// In some cases, along with the item itself, we also
     /// encode some sub-items. Usually we want some info from the item
     /// so it's easier to do that here then to wait until we would encounter
@@ -2187,11 +2174,11 @@
 }
 
 fn encode_metadata_impl(tcx: TyCtxt<'_>) -> EncodedMetadata {
-    let mut encoder = opaque::Encoder::new(vec![]);
-    encoder.emit_raw_bytes(METADATA_HEADER).unwrap();
+    let mut encoder = MemEncoder::new();
+    encoder.emit_raw_bytes(METADATA_HEADER);
 
     // Will be filled with the root position after encoding everything.
-    encoder.emit_raw_bytes(&[0, 0, 0, 0]).unwrap();
+    encoder.emit_raw_bytes(&[0, 0, 0, 0]);
 
     let source_map_files = tcx.sess.source_map().files();
     let source_file_cache = (source_map_files[0].clone(), 0);
@@ -2216,13 +2203,13 @@
     };
 
     // Encode the rustc version string in a predictable location.
-    rustc_version().encode(&mut ecx).unwrap();
+    rustc_version().encode(&mut ecx);
 
     // Encode all the entries and extra information in the crate,
     // culminating in the `CrateRoot` which points to all of it.
     let root = ecx.encode_crate_root();
 
-    let mut result = ecx.opaque.into_inner();
+    let mut result = ecx.opaque.finish();
 
     // Encode the root position.
     let header = METADATA_HEADER.len();
@@ -2243,26 +2230,16 @@
         traits_in_crate: |tcx, cnum| {
             assert_eq!(cnum, LOCAL_CRATE);
 
-            #[derive(Default)]
-            struct TraitsVisitor {
-                traits: Vec<DefId>,
-            }
-            impl ItemLikeVisitor<'_> for TraitsVisitor {
-                fn visit_item(&mut self, item: &hir::Item<'_>) {
-                    if let hir::ItemKind::Trait(..) | hir::ItemKind::TraitAlias(..) = item.kind {
-                        self.traits.push(item.def_id.to_def_id());
-                    }
+            let mut traits = Vec::new();
+            for id in tcx.hir().items() {
+                if matches!(tcx.def_kind(id.def_id), DefKind::Trait | DefKind::TraitAlias) {
+                    traits.push(id.def_id.to_def_id())
                 }
-                fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem<'_>) {}
-                fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem<'_>) {}
-                fn visit_foreign_item(&mut self, _foreign_item: &hir::ForeignItem<'_>) {}
             }
 
-            let mut visitor = TraitsVisitor::default();
-            tcx.hir().visit_all_item_likes(&mut visitor);
             // Bring everything into deterministic order.
-            visitor.traits.sort_by_cached_key(|&def_id| tcx.def_path_hash(def_id));
-            tcx.arena.alloc_slice(&visitor.traits)
+            traits.sort_by_cached_key(|&def_id| tcx.def_path_hash(def_id));
+            tcx.arena.alloc_slice(&traits)
         },
 
         ..*providers
diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs
index 356dad4..a58c0e6 100644
--- a/compiler/rustc_metadata/src/rmeta/mod.rs
+++ b/compiler/rustc_metadata/src/rmeta/mod.rs
@@ -1,7 +1,7 @@
 use crate::creader::CrateMetadataRef;
 use decoder::Metadata;
 use def_path_hash_map::DefPathHashMapRef;
-use table::{Table, TableBuilder};
+use table::TableBuilder;
 
 use rustc_ast as ast;
 use rustc_attr as attr;
@@ -20,9 +20,9 @@
 use rustc_middle::thir;
 use rustc_middle::ty::fast_reject::SimplifiedType;
 use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::GeneratorDiagnosticData;
 use rustc_middle::ty::{self, ReprOptions, Ty};
-use rustc_serialize::opaque::Encoder;
+use rustc_middle::ty::{GeneratorDiagnosticData, ParameterizedOverTcx, TyCtxt};
+use rustc_serialize::opaque::MemEncoder;
 use rustc_session::config::SymbolManglingVersion;
 use rustc_session::cstore::{CrateDepKind, ForeignModule, LinkagePreference, NativeLib};
 use rustc_span::edition::Edition;
@@ -36,7 +36,7 @@
 
 pub use decoder::provide_extern;
 use decoder::DecodeContext;
-crate use decoder::{CrateMetadata, CrateNumMap, MetadataBlob};
+pub(crate) use decoder::{CrateMetadata, CrateNumMap, MetadataBlob};
 use encoder::EncodeContext;
 pub use encoder::{encode_metadata, EncodedMetadata};
 use rustc_span::hygiene::SyntaxContextData;
@@ -46,7 +46,7 @@
 mod encoder;
 mod table;
 
-crate fn rustc_version() -> String {
+pub(crate) fn rustc_version() -> String {
     format!("rustc {}", option_env!("CFG_VERSION").unwrap_or("unknown version"))
 }
 
@@ -62,20 +62,6 @@
 /// and further followed by the rustc version string.
 pub const METADATA_HEADER: &[u8] = &[b'r', b'u', b's', b't', 0, 0, 0, METADATA_VERSION];
 
-/// Additional metadata for a `Lazy<T>` where `T` may not be `Sized`,
-/// e.g. for `Lazy<[T]>`, this is the length (count of `T` values).
-trait LazyMeta {
-    type Meta: Copy + 'static;
-}
-
-impl<T> LazyMeta for T {
-    type Meta = ();
-}
-
-impl<T> LazyMeta for [T] {
-    type Meta = usize;
-}
-
 /// A value of type T referred to by its absolute position
 /// in the metadata, and which can be decoded lazily.
 ///
@@ -91,8 +77,23 @@
 /// Distances start at 1, as 0-byte nodes are invalid.
 /// Also invalid are nodes being referred in a different
 /// order than they were encoded in.
-///
-/// # Sequences (`Lazy<[T]>`)
+#[must_use]
+struct LazyValue<T> {
+    position: NonZeroUsize,
+    _marker: PhantomData<fn() -> T>,
+}
+
+impl<T: ParameterizedOverTcx> ParameterizedOverTcx for LazyValue<T> {
+    type Value<'tcx> = LazyValue<T::Value<'tcx>>;
+}
+
+impl<T> LazyValue<T> {
+    fn from_position(position: NonZeroUsize) -> LazyValue<T> {
+        LazyValue { position, _marker: PhantomData }
+    }
+}
+
+/// A list of lazily-decoded values.
 ///
 /// Unlike `Lazy<Vec<T>>`, the length is encoded next to the
 /// position, not at the position, which means that the length
@@ -102,39 +103,66 @@
 /// the encoding is that of `Lazy`, with the distinction that
 /// the minimal distance the length of the sequence, i.e.
 /// it's assumed there's no 0-byte element in the sequence.
-#[must_use]
-// FIXME(#59875) the `Meta` parameter only exists to dodge
-// invariance wrt `T` (coming from the `meta: T::Meta` field).
-struct Lazy<T, Meta = <T as LazyMeta>::Meta>
-where
-    T: ?Sized + LazyMeta<Meta = Meta>,
-    Meta: 'static + Copy,
-{
+struct LazyArray<T> {
     position: NonZeroUsize,
-    meta: Meta,
-    _marker: PhantomData<T>,
+    num_elems: usize,
+    _marker: PhantomData<fn() -> T>,
 }
 
-impl<T: ?Sized + LazyMeta> Lazy<T> {
-    fn from_position_and_meta(position: NonZeroUsize, meta: T::Meta) -> Lazy<T> {
-        Lazy { position, meta, _marker: PhantomData }
+impl<T: ParameterizedOverTcx> ParameterizedOverTcx for LazyArray<T> {
+    type Value<'tcx> = LazyArray<T::Value<'tcx>>;
+}
+
+impl<T> LazyArray<T> {
+    fn from_position_and_num_elems(position: NonZeroUsize, num_elems: usize) -> LazyArray<T> {
+        LazyArray { position, num_elems, _marker: PhantomData }
+    }
+
+    fn empty() -> LazyArray<T> {
+        LazyArray::from_position_and_num_elems(NonZeroUsize::new(1).unwrap(), 0)
     }
 }
 
-impl<T> Lazy<T> {
-    fn from_position(position: NonZeroUsize) -> Lazy<T> {
-        Lazy::from_position_and_meta(position, ())
+/// A list of lazily-decoded values, with the added capability of random access.
+///
+/// Random-access table (i.e. offering constant-time `get`/`set`), similar to
+/// `LazyArray<T>`, but without requiring encoding or decoding all the values
+/// eagerly and in-order.
+struct LazyTable<I, T> {
+    position: NonZeroUsize,
+    encoded_size: usize,
+    _marker: PhantomData<fn(I) -> T>,
+}
+
+impl<I: 'static, T: ParameterizedOverTcx> ParameterizedOverTcx for LazyTable<I, T> {
+    type Value<'tcx> = LazyTable<I, T::Value<'tcx>>;
+}
+
+impl<I, T> LazyTable<I, T> {
+    fn from_position_and_encoded_size(
+        position: NonZeroUsize,
+        encoded_size: usize,
+    ) -> LazyTable<I, T> {
+        LazyTable { position, encoded_size, _marker: PhantomData }
     }
 }
 
-impl<T> Lazy<[T]> {
-    fn empty() -> Lazy<[T]> {
-        Lazy::from_position_and_meta(NonZeroUsize::new(1).unwrap(), 0)
+impl<T> Copy for LazyValue<T> {}
+impl<T> Clone for LazyValue<T> {
+    fn clone(&self) -> Self {
+        *self
     }
 }
 
-impl<T: ?Sized + LazyMeta> Copy for Lazy<T> {}
-impl<T: ?Sized + LazyMeta> Clone for Lazy<T> {
+impl<T> Copy for LazyArray<T> {}
+impl<T> Clone for LazyArray<T> {
+    fn clone(&self) -> Self {
+        *self
+    }
+}
+
+impl<I, T> Copy for LazyTable<I, T> {}
+impl<I, T> Clone for LazyTable<I, T> {
     fn clone(&self) -> Self {
         *self
     }
@@ -155,29 +183,20 @@
     Previous(NonZeroUsize),
 }
 
-// FIXME(#59875) `Lazy!(T)` replaces `Lazy<T>`, passing the `Meta` parameter
-// manually, instead of relying on the default, to get the correct variance.
-// Only needed when `T` itself contains a parameter (e.g. `'tcx`).
-macro_rules! Lazy {
-    (Table<$I:ty, $T:ty>) => {Lazy<Table<$I, $T>, usize>};
-    ([$T:ty]) => {Lazy<[$T], usize>};
-    ($T:ty) => {Lazy<$T, ()>};
-}
-
-type SyntaxContextTable = Lazy<Table<u32, Lazy<SyntaxContextData>>>;
-type ExpnDataTable = Lazy<Table<ExpnIndex, Lazy<ExpnData>>>;
-type ExpnHashTable = Lazy<Table<ExpnIndex, Lazy<ExpnHash>>>;
+type SyntaxContextTable = LazyTable<u32, LazyValue<SyntaxContextData>>;
+type ExpnDataTable = LazyTable<ExpnIndex, LazyValue<ExpnData>>;
+type ExpnHashTable = LazyTable<ExpnIndex, LazyValue<ExpnHash>>;
 
 #[derive(MetadataEncodable, MetadataDecodable)]
-crate struct ProcMacroData {
+pub(crate) struct ProcMacroData {
     proc_macro_decls_static: DefIndex,
     stability: Option<attr::Stability>,
-    macros: Lazy<[DefIndex]>,
+    macros: LazyArray<DefIndex>,
 }
 
 /// Serialized metadata for a crate.
 /// When compiling a proc-macro crate, we encode many of
-/// the `Lazy<[T]>` fields as `Lazy::empty()`. This serves two purposes:
+/// the `LazyArray<T>` fields as `Lazy::empty()`. This serves two purposes:
 ///
 /// 1. We avoid performing unnecessary work. Proc-macro crates can only
 /// export proc-macros functions, which are compiled into a shared library.
@@ -192,7 +211,7 @@
 /// a normal crate, much of what we serialized would be unusable in addition
 /// to being unused.
 #[derive(MetadataEncodable, MetadataDecodable)]
-crate struct CrateRoot<'tcx> {
+pub(crate) struct CrateRoot {
     name: Symbol,
     triple: TargetTriple,
     extra_filename: String,
@@ -205,32 +224,32 @@
     has_panic_handler: bool,
     has_default_lib_allocator: bool,
 
-    crate_deps: Lazy<[CrateDep]>,
-    dylib_dependency_formats: Lazy<[Option<LinkagePreference>]>,
-    lib_features: Lazy<[(Symbol, Option<Symbol>)]>,
-    lang_items: Lazy<[(DefIndex, usize)]>,
-    lang_items_missing: Lazy<[lang_items::LangItem]>,
-    diagnostic_items: Lazy<[(Symbol, DefIndex)]>,
-    native_libraries: Lazy<[NativeLib]>,
-    foreign_modules: Lazy<[ForeignModule]>,
-    traits: Lazy<[DefIndex]>,
-    impls: Lazy<[TraitImpls]>,
-    incoherent_impls: Lazy<[IncoherentImpls]>,
-    interpret_alloc_index: Lazy<[u32]>,
+    crate_deps: LazyArray<CrateDep>,
+    dylib_dependency_formats: LazyArray<Option<LinkagePreference>>,
+    lib_features: LazyArray<(Symbol, Option<Symbol>)>,
+    lang_items: LazyArray<(DefIndex, usize)>,
+    lang_items_missing: LazyArray<lang_items::LangItem>,
+    diagnostic_items: LazyArray<(Symbol, DefIndex)>,
+    native_libraries: LazyArray<NativeLib>,
+    foreign_modules: LazyArray<ForeignModule>,
+    traits: LazyArray<DefIndex>,
+    impls: LazyArray<TraitImpls>,
+    incoherent_impls: LazyArray<IncoherentImpls>,
+    interpret_alloc_index: LazyArray<u32>,
     proc_macro_data: Option<ProcMacroData>,
 
-    tables: LazyTables<'tcx>,
-    debugger_visualizers: Lazy<[rustc_span::DebuggerVisualizerFile]>,
+    tables: LazyTables,
+    debugger_visualizers: LazyArray<rustc_span::DebuggerVisualizerFile>,
 
-    exported_symbols: Lazy!([(ExportedSymbol<'tcx>, SymbolExportInfo)]),
+    exported_symbols: LazyArray<(ExportedSymbol<'static>, SymbolExportInfo)>,
 
     syntax_contexts: SyntaxContextTable,
     expn_data: ExpnDataTable,
     expn_hashes: ExpnHashTable,
 
-    def_path_hash_map: Lazy<DefPathHashMapRef<'tcx>>,
+    def_path_hash_map: LazyValue<DefPathHashMapRef<'static>>,
 
-    source_map: Lazy<[rustc_span::SourceFile]>,
+    source_map: LazyArray<rustc_span::SourceFile>,
 
     compiler_builtins: bool,
     needs_allocator: bool,
@@ -245,7 +264,7 @@
 /// This creates a type-safe way to enforce that we remap the CrateNum between the on-disk
 /// representation and the compilation session.
 #[derive(Copy, Clone)]
-crate struct RawDefId {
+pub(crate) struct RawDefId {
     krate: u32,
     index: u32,
 }
@@ -257,7 +276,12 @@
 }
 
 impl RawDefId {
-    fn decode(self, cdata: CrateMetadataRef<'_>) -> DefId {
+    /// This exists so that `provide_one!` is happy
+    fn decode(self, meta: (CrateMetadataRef<'_>, TyCtxt<'_>)) -> DefId {
+        self.decode_from_cdata(meta.0)
+    }
+
+    fn decode_from_cdata(self, cdata: CrateMetadataRef<'_>) -> DefId {
         let krate = CrateNum::from_u32(self.krate);
         let krate = cdata.map_encoded_cnum_to_current(krate);
         DefId { krate, index: DefIndex::from_u32(self.index) }
@@ -265,7 +289,7 @@
 }
 
 #[derive(Encodable, Decodable)]
-crate struct CrateDep {
+pub(crate) struct CrateDep {
     pub name: Symbol,
     pub hash: Svh,
     pub host_hash: Option<Svh>,
@@ -274,32 +298,32 @@
 }
 
 #[derive(MetadataEncodable, MetadataDecodable)]
-crate struct TraitImpls {
+pub(crate) struct TraitImpls {
     trait_id: (u32, DefIndex),
-    impls: Lazy<[(DefIndex, Option<SimplifiedType>)]>,
+    impls: LazyArray<(DefIndex, Option<SimplifiedType>)>,
 }
 
 #[derive(MetadataEncodable, MetadataDecodable)]
-crate struct IncoherentImpls {
+pub(crate) struct IncoherentImpls {
     self_ty: SimplifiedType,
-    impls: Lazy<[DefIndex]>,
+    impls: LazyArray<DefIndex>,
 }
 
 /// Define `LazyTables` and `TableBuilders` at the same time.
 macro_rules! define_tables {
     ($($name:ident: Table<$IDX:ty, $T:ty>),+ $(,)?) => {
         #[derive(MetadataEncodable, MetadataDecodable)]
-        crate struct LazyTables<'tcx> {
-            $($name: Lazy!(Table<$IDX, $T>)),+
+        pub(crate) struct LazyTables {
+            $($name: LazyTable<$IDX, $T>),+
         }
 
         #[derive(Default)]
-        struct TableBuilders<'tcx> {
+        struct TableBuilders {
             $($name: TableBuilder<$IDX, $T>),+
         }
 
-        impl<'tcx> TableBuilders<'tcx> {
-            fn encode(&self, buf: &mut Encoder) -> LazyTables<'tcx> {
+        impl TableBuilders {
+            fn encode(&self, buf: &mut MemEncoder) -> LazyTables {
                 LazyTables {
                     $($name: self.$name.encode(buf)),+
                 }
@@ -309,60 +333,62 @@
 }
 
 define_tables! {
-    kind: Table<DefIndex, Lazy<EntryKind>>,
-    attributes: Table<DefIndex, Lazy<[ast::Attribute]>>,
-    children: Table<DefIndex, Lazy<[DefIndex]>>,
+    kind: Table<DefIndex, LazyValue<EntryKind>>,
+    attributes: Table<DefIndex, LazyArray<ast::Attribute>>,
+    children: Table<DefIndex, LazyArray<DefIndex>>,
 
     opt_def_kind: Table<DefIndex, DefKind>,
-    visibility: Table<DefIndex, Lazy<ty::Visibility>>,
-    def_span: Table<DefIndex, Lazy<Span>>,
-    def_ident_span: Table<DefIndex, Lazy<Span>>,
-    lookup_stability: Table<DefIndex, Lazy<attr::Stability>>,
-    lookup_const_stability: Table<DefIndex, Lazy<attr::ConstStability>>,
-    lookup_deprecation_entry: Table<DefIndex, Lazy<attr::Deprecation>>,
+    visibility: Table<DefIndex, LazyValue<ty::Visibility>>,
+    def_span: Table<DefIndex, LazyValue<Span>>,
+    def_ident_span: Table<DefIndex, LazyValue<Span>>,
+    lookup_stability: Table<DefIndex, LazyValue<attr::Stability>>,
+    lookup_const_stability: Table<DefIndex, LazyValue<attr::ConstStability>>,
+    lookup_deprecation_entry: Table<DefIndex, LazyValue<attr::Deprecation>>,
     // As an optimization, a missing entry indicates an empty `&[]`.
-    explicit_item_bounds: Table<DefIndex, Lazy!([(ty::Predicate<'tcx>, Span)])>,
-    explicit_predicates_of: Table<DefIndex, Lazy!(ty::GenericPredicates<'tcx>)>,
-    generics_of: Table<DefIndex, Lazy<ty::Generics>>,
+    explicit_item_bounds: Table<DefIndex, LazyArray<(ty::Predicate<'static>, Span)>>,
+    explicit_predicates_of: Table<DefIndex, LazyValue<ty::GenericPredicates<'static>>>,
+    generics_of: Table<DefIndex, LazyValue<ty::Generics>>,
     // As an optimization, a missing entry indicates an empty `&[]`.
-    inferred_outlives_of: Table<DefIndex, Lazy!([(ty::Predicate<'tcx>, Span)])>,
-    super_predicates_of: Table<DefIndex, Lazy!(ty::GenericPredicates<'tcx>)>,
-    type_of: Table<DefIndex, Lazy!(Ty<'tcx>)>,
-    variances_of: Table<DefIndex, Lazy<[ty::Variance]>>,
-    fn_sig: Table<DefIndex, Lazy!(ty::PolyFnSig<'tcx>)>,
-    codegen_fn_attrs: Table<DefIndex, Lazy!(CodegenFnAttrs)>,
-    impl_trait_ref: Table<DefIndex, Lazy!(ty::TraitRef<'tcx>)>,
-    const_param_default: Table<DefIndex, Lazy<rustc_middle::ty::Const<'tcx>>>,
-    optimized_mir: Table<DefIndex, Lazy!(mir::Body<'tcx>)>,
-    mir_for_ctfe: Table<DefIndex, Lazy!(mir::Body<'tcx>)>,
-    promoted_mir: Table<DefIndex, Lazy!(IndexVec<mir::Promoted, mir::Body<'tcx>>)>,
-    thir_abstract_const: Table<DefIndex, Lazy!(&'tcx [thir::abstract_const::Node<'tcx>])>,
+    inferred_outlives_of: Table<DefIndex, LazyArray<(ty::Predicate<'static>, Span)>>,
+    super_predicates_of: Table<DefIndex, LazyValue<ty::GenericPredicates<'static>>>,
+    type_of: Table<DefIndex, LazyValue<Ty<'static>>>,
+    variances_of: Table<DefIndex, LazyArray<ty::Variance>>,
+    fn_sig: Table<DefIndex, LazyValue<ty::PolyFnSig<'static>>>,
+    codegen_fn_attrs: Table<DefIndex, LazyValue<CodegenFnAttrs>>,
+    impl_trait_ref: Table<DefIndex, LazyValue<ty::TraitRef<'static>>>,
+    const_param_default: Table<DefIndex, LazyValue<rustc_middle::ty::Const<'static>>>,
+    optimized_mir: Table<DefIndex, LazyValue<mir::Body<'static>>>,
+    mir_for_ctfe: Table<DefIndex, LazyValue<mir::Body<'static>>>,
+    promoted_mir: Table<DefIndex, LazyValue<IndexVec<mir::Promoted, mir::Body<'static>>>>,
+    // FIXME(compiler-errors): Why isn't this a LazyArray?
+    thir_abstract_const: Table<DefIndex, LazyValue<&'static [thir::abstract_const::Node<'static>]>>,
     impl_parent: Table<DefIndex, RawDefId>,
     impl_polarity: Table<DefIndex, ty::ImplPolarity>,
-    impl_constness: Table<DefIndex, hir::Constness>,
+    constness: Table<DefIndex, hir::Constness>,
+    is_intrinsic: Table<DefIndex, ()>,
     impl_defaultness: Table<DefIndex, hir::Defaultness>,
     // FIXME(eddyb) perhaps compute this on the fly if cheap enough?
-    coerce_unsized_info: Table<DefIndex, Lazy!(ty::adjustment::CoerceUnsizedInfo)>,
-    mir_const_qualif: Table<DefIndex, Lazy!(mir::ConstQualifs)>,
-    rendered_const: Table<DefIndex, Lazy!(String)>,
+    coerce_unsized_info: Table<DefIndex, LazyValue<ty::adjustment::CoerceUnsizedInfo>>,
+    mir_const_qualif: Table<DefIndex, LazyValue<mir::ConstQualifs>>,
+    rendered_const: Table<DefIndex, LazyValue<String>>,
     asyncness: Table<DefIndex, hir::IsAsync>,
-    fn_arg_names: Table<DefIndex, Lazy!([Ident])>,
-    generator_kind: Table<DefIndex, Lazy!(hir::GeneratorKind)>,
-    trait_def: Table<DefIndex, Lazy!(ty::TraitDef)>,
+    fn_arg_names: Table<DefIndex, LazyArray<Ident>>,
+    generator_kind: Table<DefIndex, LazyValue<hir::GeneratorKind>>,
+    trait_def: Table<DefIndex, LazyValue<ty::TraitDef>>,
 
     trait_item_def_id: Table<DefIndex, RawDefId>,
-    inherent_impls: Table<DefIndex, Lazy<[DefIndex]>>,
-    expn_that_defined: Table<DefIndex, Lazy<ExpnId>>,
-    unused_generic_params: Table<DefIndex, Lazy<FiniteBitSet<u32>>>,
-    repr_options: Table<DefIndex, Lazy<ReprOptions>>,
+    inherent_impls: Table<DefIndex, LazyArray<DefIndex>>,
+    expn_that_defined: Table<DefIndex, LazyValue<ExpnId>>,
+    unused_generic_params: Table<DefIndex, LazyValue<FiniteBitSet<u32>>>,
+    repr_options: Table<DefIndex, LazyValue<ReprOptions>>,
     // `def_keys` and `def_path_hashes` represent a lazy version of a
     // `DefPathTable`. This allows us to avoid deserializing an entire
     // `DefPathTable` up front, since we may only ever use a few
     // definitions from any given crate.
-    def_keys: Table<DefIndex, Lazy<DefKey>>,
+    def_keys: Table<DefIndex, LazyValue<DefKey>>,
     def_path_hashes: Table<DefIndex, DefPathHash>,
-    proc_macro_quoted_spans: Table<usize, Lazy<Span>>,
-    generator_diagnostic_data: Table<DefIndex, Lazy<GeneratorDiagnosticData<'tcx>>>,
+    proc_macro_quoted_spans: Table<usize, LazyValue<Span>>,
+    generator_diagnostic_data: Table<DefIndex, LazyValue<GeneratorDiagnosticData<'static>>>,
     may_have_doc_links: Table<DefIndex, ()>,
 }
 
@@ -381,19 +407,19 @@
     OpaqueTy,
     Enum,
     Field,
-    Variant(Lazy<VariantData>),
-    Struct(Lazy<VariantData>),
-    Union(Lazy<VariantData>),
+    Variant(LazyValue<VariantData>),
+    Struct(LazyValue<VariantData>),
+    Union(LazyValue<VariantData>),
     Fn,
     ForeignFn,
-    Mod(Lazy<[ModChild]>),
-    MacroDef(Lazy<ast::MacArgs>, /*macro_rules*/ bool),
+    Mod(LazyArray<ModChild>),
+    MacroDef(LazyValue<ast::MacArgs>, /*macro_rules*/ bool),
     ProcMacro(MacroKind),
     Closure,
     Generator,
     Trait,
     Impl,
-    AssocFn(Lazy<AssocFnData>),
+    AssocFn(LazyValue<AssocFnData>),
     AssocType(AssocContainer),
     AssocConst(AssocContainer),
     TraitAlias,
@@ -463,3 +489,14 @@
     encoder::provide(providers);
     decoder::provide(providers);
 }
+
+trivially_parameterized_over_tcx! {
+    VariantData,
+    AssocFnData,
+    EntryKind,
+    RawDefId,
+    TraitImpls,
+    IncoherentImpls,
+    CrateRoot,
+    CrateDep,
+}
diff --git a/compiler/rustc_metadata/src/rmeta/table.rs b/compiler/rustc_metadata/src/rmeta/table.rs
index 53fc2ef..5ab4269 100644
--- a/compiler/rustc_metadata/src/rmeta/table.rs
+++ b/compiler/rustc_metadata/src/rmeta/table.rs
@@ -3,8 +3,9 @@
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_hir::def::{CtorKind, CtorOf};
 use rustc_index::vec::Idx;
-use rustc_serialize::opaque::Encoder;
-use rustc_serialize::Encoder as _;
+use rustc_middle::ty::ParameterizedOverTcx;
+use rustc_serialize::opaque::MemEncoder;
+use rustc_serialize::Encoder;
 use rustc_span::hygiene::MacroKind;
 use std::convert::TryInto;
 use std::marker::PhantomData;
@@ -201,15 +202,15 @@
 }
 
 // NOTE(eddyb) there could be an impl for `usize`, which would enable a more
-// generic `Lazy<T>` impl, but in the general case we might not need / want to
-// fit every `usize` in `u32`.
-impl<T> FixedSizeEncoding for Option<Lazy<T>> {
+// generic `LazyValue<T>` impl, but in the general case we might not need / want
+// to fit every `usize` in `u32`.
+impl<T> FixedSizeEncoding for Option<LazyValue<T>> {
     type ByteArray = [u8; 4];
 
     #[inline]
     fn from_bytes(b: &[u8; 4]) -> Self {
         let position = NonZeroUsize::new(u32::from_bytes(b) as usize)?;
-        Some(Lazy::from_position(position))
+        Some(LazyValue::from_position(position))
     }
 
     #[inline]
@@ -220,7 +221,7 @@
     }
 }
 
-impl<T> FixedSizeEncoding for Option<Lazy<[T]>> {
+impl<T> FixedSizeEncoding for Option<LazyArray<T>> {
     type ByteArray = [u8; 8];
 
     #[inline]
@@ -228,7 +229,7 @@
         let ([ref position_bytes, ref meta_bytes],[])= b.as_chunks::<4>() else { panic!() };
         let position = NonZeroUsize::new(u32::from_bytes(position_bytes) as usize)?;
         let len = u32::from_bytes(meta_bytes) as usize;
-        Some(Lazy::from_position_and_meta(position, len))
+        Some(LazyArray::from_position_and_num_elems(position, len))
     }
 
     #[inline]
@@ -239,28 +240,12 @@
         let position: u32 = position.try_into().unwrap();
         position.write_to_bytes(position_bytes);
 
-        let len = self.map_or(0, |lazy| lazy.meta);
+        let len = self.map_or(0, |lazy| lazy.num_elems);
         let len: u32 = len.try_into().unwrap();
         len.write_to_bytes(meta_bytes);
     }
 }
 
-/// Random-access table (i.e. offering constant-time `get`/`set`), similar to
-/// `Vec<Option<T>>`, but without requiring encoding or decoding all the values
-/// eagerly and in-order.
-/// A total of `(max_idx + 1)` times `Option<T> as FixedSizeEncoding>::ByteArray`
-/// are used for a table, where `max_idx` is the largest index passed to
-/// `TableBuilder::set`.
-pub(super) struct Table<I: Idx, T>
-where
-    Option<T>: FixedSizeEncoding,
-{
-    _marker: PhantomData<(fn(&I), T)>,
-    // NOTE(eddyb) this makes `Table` not implement `Sized`, but no
-    // value of `Table` is ever created (it's always behind `Lazy`).
-    _bytes: [u8],
-}
-
 /// Helper for constructing a table's serialization (also see `Table`).
 pub(super) struct TableBuilder<I: Idx, T>
 where
@@ -296,28 +281,23 @@
         Some(value).write_to_bytes(&mut self.blocks[i]);
     }
 
-    pub(crate) fn encode<const N: usize>(&self, buf: &mut Encoder) -> Lazy<Table<I, T>>
+    pub(crate) fn encode<const N: usize>(&self, buf: &mut MemEncoder) -> LazyTable<I, T>
     where
         Option<T>: FixedSizeEncoding<ByteArray = [u8; N]>,
     {
         let pos = buf.position();
         for block in &self.blocks {
-            buf.emit_raw_bytes(block).unwrap();
+            buf.emit_raw_bytes(block);
         }
         let num_bytes = self.blocks.len() * N;
-        Lazy::from_position_and_meta(NonZeroUsize::new(pos as usize).unwrap(), num_bytes)
+        LazyTable::from_position_and_encoded_size(
+            NonZeroUsize::new(pos as usize).unwrap(),
+            num_bytes,
+        )
     }
 }
 
-impl<I: Idx, T> LazyMeta for Table<I, T>
-where
-    Option<T>: FixedSizeEncoding,
-{
-    /// Number of bytes in the data stream.
-    type Meta = usize;
-}
-
-impl<I: Idx, T> Lazy<Table<I, T>>
+impl<I: Idx, T: ParameterizedOverTcx> LazyTable<I, T>
 where
     Option<T>: FixedSizeEncoding,
 {
@@ -327,14 +307,14 @@
         &self,
         metadata: M,
         i: I,
-    ) -> Option<T>
+    ) -> Option<T::Value<'tcx>>
     where
-        Option<T>: FixedSizeEncoding<ByteArray = [u8; N]>,
+        Option<T::Value<'tcx>>: FixedSizeEncoding<ByteArray = [u8; N]>,
     {
-        debug!("Table::lookup: index={:?} len={:?}", i, self.meta);
+        debug!("LazyTable::lookup: index={:?} len={:?}", i, self.encoded_size);
 
         let start = self.position.get();
-        let bytes = &metadata.blob()[start..start + self.meta];
+        let bytes = &metadata.blob()[start..start + self.encoded_size];
         let (bytes, []) = bytes.as_chunks::<N>() else { panic!() };
         let bytes = bytes.get(i.index())?;
         FixedSizeEncoding::from_bytes(bytes)
@@ -343,8 +323,8 @@
     /// Size of the table in entries, including possible gaps.
     pub(super) fn size<const N: usize>(&self) -> usize
     where
-        Option<T>: FixedSizeEncoding<ByteArray = [u8; N]>,
+        for<'tcx> Option<T::Value<'tcx>>: FixedSizeEncoding<ByteArray = [u8; N]>,
     {
-        self.meta / N
+        self.encoded_size / N
     }
 }
diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml
index cd281ea..cee8082 100644
--- a/compiler/rustc_middle/Cargo.toml
+++ b/compiler/rustc_middle/Cargo.toml
@@ -12,8 +12,8 @@
 either = "1.5.0"
 gsgdt = "0.1.2"
 tracing = "0.1"
-rustc-rayon = { version = "0.3.2", optional = true }
-rustc-rayon-core = { version = "0.3.2", optional = true }
+rustc-rayon = { version = "0.4.0", optional = true }
+rustc-rayon-core = { version = "0.4.0", optional = true }
 polonius-engine = "0.13.0"
 rustc_apfloat = { path = "../rustc_apfloat" }
 rustc_attr = { path = "../rustc_attr" }
diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs
index 7c90cbb..661a9b1 100644
--- a/compiler/rustc_middle/src/arena.rs
+++ b/compiler/rustc_middle/src/arena.rs
@@ -31,9 +31,9 @@
             [decode] unsafety_check_result: rustc_middle::mir::UnsafetyCheckResult,
             [decode] code_region: rustc_middle::mir::coverage::CodeRegion,
             [] const_allocs: rustc_middle::mir::interpret::Allocation,
+            [] region_scope_tree: rustc_middle::middle::region::ScopeTree,
             // Required for the incremental on-disk cache
             [] mir_keys: rustc_hir::def_id::DefIdSet,
-            [] region_scope_tree: rustc_middle::middle::region::ScopeTree,
             [] dropck_outlives:
                 rustc_middle::infer::canonical::Canonical<'tcx,
                     rustc_middle::infer::canonical::QueryResponse<'tcx,
@@ -82,7 +82,7 @@
             [] upvars_mentioned: rustc_data_structures::fx::FxIndexMap<rustc_hir::HirId, rustc_hir::Upvar>,
             [] object_safety_violations: rustc_middle::traits::ObjectSafetyViolation,
             [] codegen_unit: rustc_middle::mir::mono::CodegenUnit<'tcx>,
-            [] attribute: rustc_ast::Attribute,
+            [decode] attribute: rustc_ast::Attribute,
             [] name_set: rustc_data_structures::fx::FxHashSet<rustc_span::symbol::Symbol>,
             [] hir_id_set: rustc_hir::HirIdSet,
 
@@ -95,10 +95,8 @@
             // 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::InlineAsmTemplatePiece,
-
-            // This is used to decode the &'tcx [Span] for InlineAsm's line_spans.
-            [decode] span: rustc_span::Span,
             [decode] used_trait_imports: rustc_data_structures::fx::FxHashSet<rustc_hir::def_id::LocalDefId>,
+            [decode] is_late_bound_map: rustc_data_structures::fx::FxIndexSet<rustc_hir::def_id::LocalDefId>,
             [decode] impl_source: rustc_middle::traits::ImplSource<'tcx, ()>,
 
             [] dep_kind: rustc_middle::dep_graph::DepKindStruct,
diff --git a/compiler/rustc_middle/src/dep_graph/dep_node.rs b/compiler/rustc_middle/src/dep_graph/dep_node.rs
index 8402ca3..555baae 100644
--- a/compiler/rustc_middle/src/dep_graph/dep_node.rs
+++ b/compiler/rustc_middle/src/dep_graph/dep_node.rs
@@ -195,13 +195,16 @@
 
 // WARNING: `construct` is generic and does not know that `CompileCodegenUnit` takes `Symbol`s as keys.
 // Be very careful changing this type signature!
-crate fn make_compile_codegen_unit(tcx: TyCtxt<'_>, name: Symbol) -> DepNode {
+pub(crate) fn make_compile_codegen_unit(tcx: TyCtxt<'_>, name: Symbol) -> DepNode {
     DepNode::construct(tcx, DepKind::CompileCodegenUnit, &name)
 }
 
 // WARNING: `construct` is generic and does not know that `CompileMonoItem` takes `MonoItem`s as keys.
 // Be very careful changing this type signature!
-crate fn make_compile_mono_item<'tcx>(tcx: TyCtxt<'tcx>, mono_item: &MonoItem<'tcx>) -> DepNode {
+pub(crate) fn make_compile_mono_item<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    mono_item: &MonoItem<'tcx>,
+) -> DepNode {
     DepNode::construct(tcx, DepKind::CompileMonoItem, mono_item)
 }
 
diff --git a/compiler/rustc_middle/src/dep_graph/mod.rs b/compiler/rustc_middle/src/dep_graph/mod.rs
index 6bfd1b7..e335cb3 100644
--- a/compiler/rustc_middle/src/dep_graph/mod.rs
+++ b/compiler/rustc_middle/src/dep_graph/mod.rs
@@ -12,7 +12,7 @@
 };
 
 pub use dep_node::{label_strs, DepKind, DepKindStruct, DepNode, DepNodeExt};
-crate use dep_node::{make_compile_codegen_unit, make_compile_mono_item};
+pub(crate) use dep_node::{make_compile_codegen_unit, make_compile_mono_item};
 
 pub type DepGraph = rustc_query_system::dep_graph::DepGraph<DepKind>;
 pub type TaskDeps = rustc_query_system::dep_graph::TaskDeps<DepKind>;
diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs
index 20c8b0b..738d47b 100644
--- a/compiler/rustc_middle/src/hir/map/mod.rs
+++ b/compiler/rustc_middle/src/hir/map/mod.rs
@@ -9,7 +9,6 @@
 use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE};
 use rustc_hir::definitions::{DefKey, DefPath, DefPathHash};
 use rustc_hir::intravisit::{self, Visitor};
-use rustc_hir::itemlikevisit::ItemLikeVisitor;
 use rustc_hir::*;
 use rustc_index::vec::Idx;
 use rustc_middle::hir::nested_filter;
@@ -23,7 +22,7 @@
         Node::Item(Item { kind: ItemKind::Fn(sig, _, _), .. })
         | Node::TraitItem(TraitItem { kind: TraitItemKind::Fn(sig, _), .. })
         | Node::ImplItem(ImplItem { kind: ImplItemKind::Fn(sig, _), .. }) => Some(&sig.decl),
-        Node::Expr(Expr { kind: ExprKind::Closure(_, fn_decl, ..), .. })
+        Node::Expr(Expr { kind: ExprKind::Closure { fn_decl, .. }, .. })
         | Node::ForeignItem(ForeignItem { kind: ForeignItemKind::Fn(fn_decl, ..), .. }) => {
             Some(fn_decl)
         }
@@ -55,7 +54,7 @@
             kind: ImplItemKind::Const(_, body) | ImplItemKind::Fn(_, body),
             ..
         })
-        | Node::Expr(Expr { kind: ExprKind::Closure(.., body, _, _), .. }) => Some(*body),
+        | Node::Expr(Expr { kind: ExprKind::Closure { body, .. }, .. }) => Some(*body),
 
         Node::AnonConst(constant) => Some(constant.body),
 
@@ -161,13 +160,17 @@
         self.tcx.hir_crate_items(()).items.iter().copied()
     }
 
+    pub fn module_items(self, module: LocalDefId) -> impl Iterator<Item = ItemId> + 'hir {
+        self.tcx.hir_module_items(module).items()
+    }
+
     pub fn par_for_each_item(self, f: impl Fn(ItemId) + Sync + Send) {
         par_for_each_in(&self.tcx.hir_crate_items(()).items[..], |id| f(*id));
     }
 
     pub fn def_key(self, def_id: LocalDefId) -> DefKey {
         // Accessing the DefKey is ok, since it is part of DefPathHash.
-        self.tcx.untracked_resolutions.definitions.def_key(def_id)
+        self.tcx.definitions_untracked().def_key(def_id)
     }
 
     pub fn def_path_from_hir_id(self, id: HirId) -> Option<DefPath> {
@@ -176,13 +179,13 @@
 
     pub fn def_path(self, def_id: LocalDefId) -> DefPath {
         // Accessing the DefPath is ok, since it is part of DefPathHash.
-        self.tcx.untracked_resolutions.definitions.def_path(def_id)
+        self.tcx.definitions_untracked().def_path(def_id)
     }
 
     #[inline]
     pub fn def_path_hash(self, def_id: LocalDefId) -> DefPathHash {
         // Accessing the DefPathHash is ok, it is incr. comp. stable.
-        self.tcx.untracked_resolutions.definitions.def_path_hash(def_id)
+        self.tcx.definitions_untracked().def_path_hash(def_id)
     }
 
     #[inline]
@@ -219,7 +222,7 @@
         // Create a dependency to the crate to be sure we re-execute this when the amount of
         // definitions change.
         self.tcx.ensure().hir_crate(());
-        self.tcx.untracked_resolutions.definitions.iter_local_def_id()
+        self.tcx.definitions_untracked().iter_local_def_id()
     }
 
     pub fn opt_def_kind(self, local_def_id: LocalDefId) -> Option<DefKind> {
@@ -282,8 +285,8 @@
             }
             Node::Field(_) => DefKind::Field,
             Node::Expr(expr) => match expr.kind {
-                ExprKind::Closure(.., None) => DefKind::Closure,
-                ExprKind::Closure(.., Some(_)) => DefKind::Generator,
+                ExprKind::Closure { movability: None, .. } => DefKind::Closure,
+                ExprKind::Closure { movability: Some(_), .. } => DefKind::Generator,
                 _ => bug!("def_kind: unsupported node: {}", self.node_to_string(hir_id)),
             },
             Node::GenericParam(param) => match param.kind {
@@ -295,6 +298,7 @@
             Node::Stmt(_)
             | Node::PathSegment(_)
             | Node::Ty(_)
+            | Node::TypeBinding(_)
             | Node::Infer(_)
             | Node::TraitRef(_)
             | Node::Pat(_)
@@ -320,7 +324,8 @@
     }
 
     pub fn get_parent_node(self, hir_id: HirId) -> HirId {
-        self.find_parent_node(hir_id).unwrap()
+        self.find_parent_node(hir_id)
+            .unwrap_or_else(|| bug!("No parent for node {:?}", self.node_to_string(hir_id)))
     }
 
     /// Retrieves the `Node` corresponding to `id`, returning `None` if cannot be found.
@@ -358,23 +363,7 @@
 
     pub fn get_generics(self, id: LocalDefId) -> Option<&'hir Generics<'hir>> {
         let node = self.tcx.hir_owner(id)?;
-        match node.node {
-            OwnerNode::ImplItem(impl_item) => Some(&impl_item.generics),
-            OwnerNode::TraitItem(trait_item) => Some(&trait_item.generics),
-            OwnerNode::Item(Item {
-                kind:
-                    ItemKind::Fn(_, generics, _)
-                    | ItemKind::TyAlias(_, generics)
-                    | ItemKind::Enum(_, generics)
-                    | ItemKind::Struct(_, generics)
-                    | ItemKind::Union(_, generics)
-                    | ItemKind::Trait(_, _, generics, ..)
-                    | ItemKind::TraitAlias(generics, _)
-                    | ItemKind::Impl(Impl { generics, .. }),
-                ..
-            }) => Some(generics),
-            _ => None,
-        }
+        node.node.generics()
     }
 
     pub fn item(self, id: ItemId) -> &'hir Item<'hir> {
@@ -491,9 +480,7 @@
             BodyOwnerKind::Fn if self.tcx.is_const_fn_raw(def_id.to_def_id()) => {
                 ConstContext::ConstFn
             }
-            BodyOwnerKind::Fn
-                if self.tcx.has_attr(def_id.to_def_id(), sym::default_method_body_is_const) =>
-            {
+            BodyOwnerKind::Fn if self.tcx.is_const_default_method(def_id.to_def_id()) => {
                 ConstContext::ConstFn
             }
             BodyOwnerKind::Fn | BodyOwnerKind::Closure => return None,
@@ -590,12 +577,11 @@
     /// Walks the attributes in a crate.
     pub fn walk_attributes(self, visitor: &mut impl Visitor<'hir>) {
         let krate = self.krate();
-        for (owner, info) in krate.owners.iter_enumerated() {
+        for info in krate.owners.iter() {
             if let MaybeOwner::Owner(info) = info {
-                for (local_id, attrs) in info.attrs.map.iter() {
-                    let id = HirId { owner, local_id: *local_id };
+                for attrs in info.attrs.map.values() {
                     for a in *attrs {
-                        visitor.visit_attribute(id, a)
+                        visitor.visit_attribute(a)
                     }
                 }
             }
@@ -603,16 +589,16 @@
     }
 
     /// Visits all items in the crate in some deterministic (but
-    /// unspecified) order. If you just need to process every item,
-    /// but don't care about nesting, this method is the best choice.
+    /// unspecified) order. If you need to process every item,
+    /// and care about nesting -- usually because your algorithm
+    /// follows lexical scoping rules -- then this method is the best choice.
+    /// If you don't care about nesting, you should use the `tcx.hir_crate_items()` query
+    /// or `items()` instead.
     ///
-    /// If you do care about nesting -- usually because your algorithm
-    /// follows lexical scoping rules -- then you want a different
-    /// approach. You should override `visit_nested_item` in your
-    /// visitor and then call `intravisit::walk_crate` instead.
-    pub fn visit_all_item_likes<V>(self, visitor: &mut V)
+    /// Please see the notes in `intravisit.rs` for more information.
+    pub fn deep_visit_all_item_likes<V>(self, visitor: &mut V)
     where
-        V: itemlikevisit::ItemLikeVisitor<'hir>,
+        V: Visitor<'hir>,
     {
         let krate = self.krate();
         for owner in krate.owners.iter().filter_map(|i| i.as_owner()) {
@@ -643,9 +629,12 @@
         })
     }
 
-    pub fn visit_item_likes_in_module<V>(self, module: LocalDefId, visitor: &mut V)
+    /// If you don't care about nesting, you should use the
+    /// `tcx.hir_module_items()` query or `module_items()` instead.
+    /// Please see notes in `deep_visit_all_item_likes`.
+    pub fn deep_visit_item_likes_in_module<V>(self, module: LocalDefId, visitor: &mut V)
     where
-        V: ItemLikeVisitor<'hir>,
+        V: Visitor<'hir>,
     {
         let module = self.tcx.hir_module_items(module);
 
@@ -666,7 +655,7 @@
         }
     }
 
-    pub fn for_each_module(self, f: impl Fn(LocalDefId)) {
+    pub fn for_each_module(self, mut f: impl FnMut(LocalDefId)) {
         let crate_items = self.tcx.hir_crate_items(());
         for module in crate_items.submodules.iter() {
             f(*module)
@@ -768,7 +757,7 @@
                 Node::Item(_)
                 | Node::ForeignItem(_)
                 | Node::TraitItem(_)
-                | Node::Expr(Expr { kind: ExprKind::Closure(..), .. })
+                | Node::Expr(Expr { kind: ExprKind::Closure { .. }, .. })
                 | Node::ImplItem(_) => return Some(hir_id),
                 // Ignore `return`s on the first iteration
                 Node::Expr(Expr { kind: ExprKind::Loop(..) | ExprKind::Ret(..), .. })
@@ -922,27 +911,33 @@
         }
     }
 
+    #[inline]
+    fn opt_ident(self, id: HirId) -> Option<Ident> {
+        match self.get(id) {
+            Node::Binding(&Pat { kind: PatKind::Binding(_, _, ident, _), .. }) => Some(ident),
+            // A `Ctor` doesn't have an identifier itself, but its parent
+            // struct/variant does. Compare with `hir::Map::opt_span`.
+            Node::Ctor(..) => match self.find(self.get_parent_node(id))? {
+                Node::Item(item) => Some(item.ident),
+                Node::Variant(variant) => Some(variant.ident),
+                _ => unreachable!(),
+            },
+            node => node.ident(),
+        }
+    }
+
+    #[inline]
+    pub(super) fn opt_ident_span(self, id: HirId) -> Option<Span> {
+        self.opt_ident(id).map(|ident| ident.span)
+    }
+
+    #[inline]
     pub fn opt_name(self, id: HirId) -> Option<Symbol> {
-        Some(match self.get(id) {
-            Node::Item(i) => i.ident.name,
-            Node::ForeignItem(fi) => fi.ident.name,
-            Node::ImplItem(ii) => ii.ident.name,
-            Node::TraitItem(ti) => ti.ident.name,
-            Node::Variant(v) => v.ident.name,
-            Node::Field(f) => f.ident.name,
-            Node::Lifetime(lt) => lt.name.ident().name,
-            Node::GenericParam(param) => param.name.ident().name,
-            Node::Binding(&Pat { kind: PatKind::Binding(_, _, l, _), .. }) => l.name,
-            Node::Ctor(..) => self.name(HirId::make_owner(self.get_parent_item(id))),
-            _ => return None,
-        })
+        self.opt_ident(id).map(|ident| ident.name)
     }
 
     pub fn name(self, id: HirId) -> Symbol {
-        match self.opt_name(id) {
-            Some(name) => name,
-            None => bug!("no name for {}", self.node_to_string(id)),
-        }
+        self.opt_name(id).unwrap_or_else(|| bug!("no name for {}", self.node_to_string(id)))
     }
 
     /// Given a node ID, gets a list of attributes associated with the AST
@@ -979,8 +974,13 @@
             Node::AnonConst(constant) => self.body(constant.body).value.span,
             Node::Expr(expr) => expr.span,
             Node::Stmt(stmt) => stmt.span,
-            Node::PathSegment(seg) => seg.ident.span,
+            Node::PathSegment(seg) => {
+                let ident_span = seg.ident.span;
+                ident_span
+                    .with_hi(seg.args.map_or_else(|| ident_span.hi(), |args| args.span_ext.hi()))
+            }
             Node::Ty(ty) => ty.span,
+            Node::TypeBinding(tb) => tb.span,
             Node::TraitRef(tr) => tr.path.span,
             Node::Binding(pat) => pat.span,
             Node::Pat(pat) => pat.span,
@@ -1013,7 +1013,7 @@
     }
 
     pub fn span_if_local(self, id: DefId) -> Option<Span> {
-        id.as_local().and_then(|id| self.opt_span(self.local_def_id_to_hir_id(id)))
+        if id.is_local() { Some(self.tcx.def_span(id)) } else { None }
     }
 
     pub fn res_span(self, res: Res) -> Option<Span> {
@@ -1077,6 +1077,8 @@
 
     let upstream_crates = upstream_crates(tcx);
 
+    let resolutions = tcx.resolutions(());
+
     // We hash the final, remapped names of all local source files so we
     // don't have to include the path prefix remapping commandline args.
     // If we included the full mapping in the SVH, we could only have
@@ -1099,14 +1101,14 @@
     upstream_crates.hash_stable(&mut hcx, &mut stable_hasher);
     source_file_names.hash_stable(&mut hcx, &mut stable_hasher);
     if tcx.sess.opts.debugging_opts.incremental_relative_spans {
-        let definitions = &tcx.untracked_resolutions.definitions;
+        let definitions = &tcx.definitions_untracked();
         let mut owner_spans: Vec<_> = krate
             .owners
             .iter_enumerated()
             .filter_map(|(def_id, info)| {
                 let _ = info.as_owner()?;
                 let def_path_hash = definitions.def_path_hash(def_id);
-                let span = definitions.def_span(def_id);
+                let span = resolutions.source_span[def_id];
                 debug_assert_eq!(span.parent(), None);
                 Some((def_path_hash, span))
             })
@@ -1117,7 +1119,6 @@
     tcx.sess.opts.dep_tracking_hash(true).hash_stable(&mut hcx, &mut stable_hasher);
     tcx.sess.local_stable_crate_id().hash_stable(&mut hcx, &mut stable_hasher);
     // Hash visibility information since it does not appear in HIR.
-    let resolutions = tcx.resolutions(());
     resolutions.visibilities.hash_stable(&mut hcx, &mut stable_hasher);
     resolutions.has_pub_restricted.hash_stable(&mut hcx, &mut stable_hasher);
 
@@ -1130,7 +1131,7 @@
         .crates(())
         .iter()
         .map(|&cnum| {
-            let stable_crate_id = tcx.resolutions(()).cstore.stable_crate_id(cnum);
+            let stable_crate_id = tcx.stable_crate_id(cnum);
             let hash = tcx.crate_hash(cnum);
             (stable_crate_id, hash)
         })
@@ -1213,6 +1214,7 @@
         Some(Node::Stmt(_)) => node_str("stmt"),
         Some(Node::PathSegment(_)) => node_str("path segment"),
         Some(Node::Ty(_)) => node_str("type"),
+        Some(Node::TypeBinding(_)) => node_str("type binding"),
         Some(Node::TraitRef(_)) => node_str("trait ref"),
         Some(Node::Binding(_)) => node_str("local"),
         Some(Node::Pat(_)) => node_str("pat"),
diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs
index f180671..09b142e 100644
--- a/compiler/rustc_middle/src/hir/mod.rs
+++ b/compiler/rustc_middle/src/hir/mod.rs
@@ -7,13 +7,13 @@
 pub mod place;
 
 use crate::ty::query::Providers;
-use crate::ty::{ImplSubject, TyCtxt};
+use crate::ty::{DefIdTree, ImplSubject, TyCtxt};
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::*;
 use rustc_query_system::ich::StableHashingContext;
-use rustc_span::DUMMY_SP;
+use rustc_span::{ExpnId, DUMMY_SP};
 
 /// Top-level HIR node for current owner. This only contains the node for which
 /// `HirId::local_id == 0`, and excludes bodies.
@@ -36,7 +36,7 @@
 
 /// Gather the LocalDefId for each item-like within a module, including items contained within
 /// bodies.  The Ids are in visitor order.  This is used to partition a pass between modules.
-#[derive(Debug, HashStable)]
+#[derive(Debug, HashStable, Encodable, Decodable)]
 pub struct ModuleItems {
     submodules: Box<[LocalDefId]>,
     items: Box<[ItemId]>,
@@ -104,24 +104,31 @@
     };
     providers.hir_owner_nodes = |tcx, id| tcx.hir_crate(()).owners[id].map(|i| &i.nodes);
     providers.hir_owner_parent = |tcx, id| {
-        // Accessing the def_key is ok since its value is hashed as part of `id`'s DefPathHash.
-        let parent = tcx.untracked_resolutions.definitions.def_key(id).parent;
-        let parent = parent.map_or(CRATE_HIR_ID, |local_def_index| {
-            let def_id = LocalDefId { local_def_index };
-            let mut parent_hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
+        // Accessing the local_parent is ok since its value is hashed as part of `id`'s DefPathHash.
+        tcx.opt_local_parent(id).map_or(CRATE_HIR_ID, |parent| {
+            let mut parent_hir_id = tcx.hir().local_def_id_to_hir_id(parent);
             if let Some(local_id) =
                 tcx.hir_crate(()).owners[parent_hir_id.owner].unwrap().parenting.get(&id)
             {
                 parent_hir_id.local_id = *local_id;
             }
             parent_hir_id
-        });
-        parent
+        })
     };
     providers.hir_attrs =
         |tcx, id| tcx.hir_crate(()).owners[id].as_owner().map_or(AttributeMap::EMPTY, |o| &o.attrs);
-    providers.source_span = |tcx, def_id| tcx.resolutions(()).definitions.def_span(def_id);
-    providers.def_span = |tcx, def_id| tcx.hir().span_if_local(def_id).unwrap_or(DUMMY_SP);
+    providers.source_span =
+        |tcx, def_id| tcx.resolutions(()).source_span.get(def_id).copied().unwrap_or(DUMMY_SP);
+    providers.def_span = |tcx, def_id| {
+        let def_id = def_id.expect_local();
+        let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
+        tcx.hir().opt_span(hir_id).unwrap_or(DUMMY_SP)
+    };
+    providers.def_ident_span = |tcx, def_id| {
+        let def_id = def_id.expect_local();
+        let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
+        tcx.hir().opt_ident_span(hir_id)
+    };
     providers.fn_arg_names = |tcx, id| {
         let hir = tcx.hir();
         let hir_id = hir.local_def_id_to_hir_id(id.expect_local());
@@ -141,7 +148,7 @@
     providers.all_local_trait_impls = |tcx, ()| &tcx.resolutions(()).trait_impls;
     providers.expn_that_defined = |tcx, id| {
         let id = id.expect_local();
-        tcx.resolutions(()).definitions.expansion_that_defined(id)
+        tcx.resolutions(()).expn_that_defined.get(&id).copied().unwrap_or(ExpnId::root())
     };
     providers.in_scope_traits_map =
         |tcx, id| tcx.hir_crate(()).owners[id].as_owner().map(|owner_info| &owner_info.trait_map);
diff --git a/compiler/rustc_middle/src/hir/nested_filter.rs b/compiler/rustc_middle/src/hir/nested_filter.rs
index 48efae8..d56e87b 100644
--- a/compiler/rustc_middle/src/hir/nested_filter.rs
+++ b/compiler/rustc_middle/src/hir/nested_filter.rs
@@ -8,7 +8,7 @@
 /// constant arguments of types, e.g. in `let _: [(); /* HERE */];`.
 ///
 /// **This is the most common choice.** A very common pattern is
-/// to use `visit_all_item_likes()` as an outer loop,
+/// to use `deep_visit_all_item_likes()` as an outer loop,
 /// and to have the visitor that visits the contents of each item
 /// using this setting.
 pub struct OnlyBodies(());
diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs
index 6b7ac88..79f9480 100644
--- a/compiler/rustc_middle/src/infer/canonical.rs
+++ b/compiler/rustc_middle/src/infer/canonical.rs
@@ -336,7 +336,7 @@
                     GenericArgKind::Const(ct) => tcx
                         .mk_const(ty::ConstS {
                             ty: ct.ty(),
-                            val: ty::ConstKind::Bound(ty::INNERMOST, ty::BoundVar::from_u32(i)),
+                            kind: ty::ConstKind::Bound(ty::INNERMOST, ty::BoundVar::from_u32(i)),
                         })
                         .into(),
                 })
diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs
index e3522e0..46c3424 100644
--- a/compiler/rustc_middle/src/lib.rs
+++ b/compiler/rustc_middle/src/lib.rs
@@ -29,24 +29,22 @@
 #![feature(backtrace)]
 #![feature(box_patterns)]
 #![feature(core_intrinsics)]
-#![cfg_attr(bootstrap, feature(derive_default_enum))]
 #![feature(discriminant_kind)]
 #![feature(exhaustive_patterns)]
 #![feature(get_mut_unchecked)]
+#![feature(generic_associated_types)]
 #![feature(if_let_guard)]
 #![feature(map_first_last)]
 #![feature(negative_impls)]
 #![feature(never_type)]
 #![feature(extern_types)]
 #![feature(new_uninit)]
-#![feature(nll)]
 #![feature(once_cell)]
 #![feature(let_chains)]
 #![feature(let_else)]
 #![feature(min_specialization)]
 #![feature(trusted_len)]
 #![feature(type_alias_impl_trait)]
-#![feature(crate_visibility_modifier)]
 #![feature(associated_type_bounds)]
 #![feature(rustc_attrs)]
 #![feature(half_open_range_patterns)]
@@ -60,6 +58,7 @@
 #![feature(decl_macro)]
 #![feature(drain_filter)]
 #![feature(intra_doc_pointers)]
+#![feature(yeet_expr)]
 #![recursion_limit = "512"]
 #![allow(rustc::potential_query_instability)]
 
diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs
index c7c5f56..215d8de 100644
--- a/compiler/rustc_middle/src/lint.rs
+++ b/compiler/rustc_middle/src/lint.rs
@@ -115,7 +115,7 @@
 
         // Ensure that we never exceed the `--cap-lints` argument
         // unless the source is a --force-warn
-        level = if let LintLevelSource::CommandLine(_, Level::ForceWarn) = src {
+        level = if let LintLevelSource::CommandLine(_, Level::ForceWarn(_)) = src {
             level
         } else {
             cmp::min(level, self.lint_cap)
@@ -266,7 +266,7 @@
                 Level::Deny => "-D",
                 Level::Forbid => "-F",
                 Level::Allow => "-A",
-                Level::ForceWarn => "--force-warn",
+                Level::ForceWarn(_) => "--force-warn",
                 Level::Expect(_) => {
                     unreachable!("the expect level does not have a commandline flag")
                 }
@@ -352,8 +352,14 @@
                 // create a `DiagnosticBuilder` and continue as we would for warnings.
                 sess.struct_expect("", expect_id)
             }
-            (Level::Warn | Level::ForceWarn, Some(span)) => sess.struct_span_warn(span, ""),
-            (Level::Warn | Level::ForceWarn, None) => sess.struct_warn(""),
+            (Level::ForceWarn(Some(expect_id)), Some(span)) => {
+                sess.struct_span_warn_with_expectation(span, "", expect_id)
+            }
+            (Level::ForceWarn(Some(expect_id)), None) => {
+                sess.struct_warn_with_expectation("", expect_id)
+            }
+            (Level::Warn | Level::ForceWarn(None), Some(span)) => sess.struct_span_warn(span, ""),
+            (Level::Warn | Level::ForceWarn(None), None) => sess.struct_warn(""),
             (Level::Deny | Level::Forbid, Some(span)) => {
                 let mut builder = sess.diagnostic().struct_err_lint("");
                 builder.set_span(span);
@@ -398,7 +404,7 @@
         explain_lint_level_source(lint, level, src, &mut err);
 
         let name = lint.name_lower();
-        let is_force_warn = matches!(level, Level::ForceWarn);
+        let is_force_warn = matches!(level, Level::ForceWarn(_));
         err.code(DiagnosticId::Lint { name, has_future_breakage, is_force_warn });
 
         if let Some(future_incompatible) = future_incompatible {
diff --git a/compiler/rustc_middle/src/macros.rs b/compiler/rustc_middle/src/macros.rs
index 4e927f0..33b4dff 100644
--- a/compiler/rustc_middle/src/macros.rs
+++ b/compiler/rustc_middle/src/macros.rs
@@ -52,14 +52,14 @@
     (for <$tcx:lifetime> { $($ty:ty,)+ }) => {
         $(
             impl<$tcx> $crate::ty::fold::TypeFoldable<$tcx> for $ty {
-                fn try_super_fold_with<F: $crate::ty::fold::FallibleTypeFolder<$tcx>>(
+                fn try_fold_with<F: $crate::ty::fold::FallibleTypeFolder<$tcx>>(
                     self,
                     _: &mut F
                 ) -> ::std::result::Result<$ty, F::Error> {
                     Ok(self)
                 }
 
-                fn super_visit_with<F: $crate::ty::fold::TypeVisitor<$tcx>>(
+                fn visit_with<F: $crate::ty::fold::TypeVisitor<$tcx>>(
                     &self,
                     _: &mut F)
                     -> ::std::ops::ControlFlow<F::BreakTy>
@@ -95,14 +95,14 @@
         impl<$($p),*> $crate::ty::fold::TypeFoldable<$tcx> for $s
             $(where $($wc)*)*
         {
-            fn try_super_fold_with<V: $crate::ty::fold::FallibleTypeFolder<$tcx>>(
+            fn try_fold_with<V: $crate::ty::fold::FallibleTypeFolder<$tcx>>(
                 self,
                 folder: &mut V,
             ) -> ::std::result::Result<Self, V::Error> {
                 EnumTypeFoldableImpl!(@FoldVariants(self, folder) input($($variants)*) output())
             }
 
-            fn super_visit_with<V: $crate::ty::fold::TypeVisitor<$tcx>>(
+            fn visit_with<V: $crate::ty::fold::TypeVisitor<$tcx>>(
                 &self,
                 visitor: &mut V,
             ) -> ::std::ops::ControlFlow<V::BreakTy> {
diff --git a/compiler/rustc_middle/src/middle/region.rs b/compiler/rustc_middle/src/middle/region.rs
index af16e5e..c886175 100644
--- a/compiler/rustc_middle/src/middle/region.rs
+++ b/compiler/rustc_middle/src/middle/region.rs
@@ -16,6 +16,7 @@
 use rustc_span::{Span, DUMMY_SP};
 
 use std::fmt;
+use std::ops::Deref;
 
 /// Represents a statically-describable scope that can be used to
 /// bound the lifetime/region for values.
@@ -203,7 +204,7 @@
 pub type ScopeDepth = u32;
 
 /// The region scope tree encodes information about region relationships.
-#[derive(Default, Debug)]
+#[derive(TyEncodable, TyDecodable, Default, Debug)]
 pub struct ScopeTree {
     /// If not empty, this body is the root of this region hierarchy.
     pub root_body: Option<hir::HirId>,
@@ -223,15 +224,12 @@
     /// Maps from a `NodeId` to the associated destruction scope (if any).
     destruction_scopes: FxIndexMap<hir::ItemLocalId, Scope>,
 
-    /// `rvalue_scopes` includes entries for those expressions whose
-    /// cleanup scope is larger than the default. The map goes from the
-    /// expression ID to the cleanup scope id. For rvalues not present in
-    /// this table, the appropriate cleanup scope is the innermost
-    /// enclosing statement, conditional expression, or repeating
-    /// block (see `terminating_scopes`).
-    /// In constants, None is used to indicate that certain expressions
-    /// escape into 'static and should have no local cleanup scope.
-    rvalue_scopes: FxHashMap<hir::ItemLocalId, Option<Scope>>,
+    /// Identifies expressions which, if captured into a temporary, ought to
+    /// have a temporary whose lifetime extends to the end of the enclosing *block*,
+    /// and not the enclosing *statement*. Expressions that are not present in this
+    /// table are not rvalue candidates. The set of rvalue candidates is computed
+    /// during type check based on a traversal of the AST.
+    pub rvalue_candidates: FxHashMap<hir::HirId, RvalueCandidateType>,
 
     /// If there are any `yield` nested within a scope, this map
     /// stores the `Span` of the last one and its index in the
@@ -315,6 +313,17 @@
     pub body_expr_count: FxHashMap<hir::BodyId, usize>,
 }
 
+/// Identifies the reason that a given expression is an rvalue candidate
+/// (see the `rvalue_candidates` field for more information what rvalue
+/// candidates in general). In constants, the `lifetime` field is None
+/// to indicate that certain expressions escape into 'static and
+/// should have no local cleanup scope.
+#[derive(Debug, Copy, Clone, TyEncodable, TyDecodable, HashStable)]
+pub enum RvalueCandidateType {
+    Borrow { target: hir::ItemLocalId, lifetime: Option<Scope> },
+    Pattern { target: hir::ItemLocalId, lifetime: Option<Scope> },
+}
+
 #[derive(Debug, Copy, Clone, TyEncodable, TyDecodable, HashStable)]
 pub struct YieldData {
     /// The `Span` of the yield.
@@ -349,12 +358,20 @@
         self.var_map.insert(var, lifetime);
     }
 
-    pub fn record_rvalue_scope(&mut self, var: hir::ItemLocalId, lifetime: Option<Scope>) {
-        debug!("record_rvalue_scope(sub={:?}, sup={:?})", var, lifetime);
-        if let Some(lifetime) = lifetime {
-            assert!(var != lifetime.item_local_id());
+    pub fn record_rvalue_candidate(
+        &mut self,
+        var: hir::HirId,
+        candidate_type: RvalueCandidateType,
+    ) {
+        debug!("record_rvalue_candidate(var={var:?}, type={candidate_type:?})");
+        match &candidate_type {
+            RvalueCandidateType::Borrow { lifetime: Some(lifetime), .. }
+            | RvalueCandidateType::Pattern { lifetime: Some(lifetime), .. } => {
+                assert!(var.local_id != lifetime.item_local_id())
+            }
+            _ => {}
         }
-        self.rvalue_scopes.insert(var, lifetime);
+        self.rvalue_candidates.insert(var, candidate_type);
     }
 
     /// Returns the narrowest scope that encloses `id`, if any.
@@ -367,34 +384,6 @@
         self.var_map.get(&var_id).cloned()
     }
 
-    /// Returns the scope when the temp created by `expr_id` will be cleaned up.
-    pub fn temporary_scope(&self, expr_id: hir::ItemLocalId) -> Option<Scope> {
-        // Check for a designated rvalue scope.
-        if let Some(&s) = self.rvalue_scopes.get(&expr_id) {
-            debug!("temporary_scope({:?}) = {:?} [custom]", expr_id, s);
-            return s;
-        }
-
-        // Otherwise, locate the innermost terminating scope
-        // if there's one. Static items, for instance, won't
-        // have an enclosing scope, hence no scope will be
-        // returned.
-        let mut id = Scope { id: expr_id, data: ScopeData::Node };
-
-        while let Some(&(p, _)) = self.parent_map.get(&id) {
-            match p.data {
-                ScopeData::Destruction => {
-                    debug!("temporary_scope({:?}) = {:?} [enclosing]", expr_id, id);
-                    return Some(id);
-                }
-                _ => id = p,
-            }
-        }
-
-        debug!("temporary_scope({:?}) = None", expr_id);
-        None
-    }
-
     /// Returns `true` if `subscope` is equal to or is lexically nested inside `superscope`, and
     /// `false` otherwise.
     ///
@@ -419,8 +408,8 @@
 
     /// Checks whether the given scope contains a `yield`. If so,
     /// returns `Some(YieldData)`. If not, returns `None`.
-    pub fn yield_in_scope(&self, scope: Scope) -> Option<&Vec<YieldData>> {
-        self.yield_in_scope.get(&scope)
+    pub fn yield_in_scope(&self, scope: Scope) -> Option<&[YieldData]> {
+        self.yield_in_scope.get(&scope).map(Deref::deref)
     }
 
     /// Gives the number of expressions visited in a body.
@@ -439,7 +428,7 @@
             ref parent_map,
             ref var_map,
             ref destruction_scopes,
-            ref rvalue_scopes,
+            ref rvalue_candidates,
             ref yield_in_scope,
         } = *self;
 
@@ -448,7 +437,7 @@
         parent_map.hash_stable(hcx, hasher);
         var_map.hash_stable(hcx, hasher);
         destruction_scopes.hash_stable(hcx, hasher);
-        rvalue_scopes.hash_stable(hcx, hasher);
+        rvalue_candidates.hash_stable(hcx, hasher);
         yield_in_scope.hash_stable(hcx, hasher);
     }
 }
diff --git a/compiler/rustc_middle/src/middle/resolve_lifetime.rs b/compiler/rustc_middle/src/middle/resolve_lifetime.rs
index 70586ce..c71ba7b 100644
--- a/compiler/rustc_middle/src/middle/resolve_lifetime.rs
+++ b/compiler/rustc_middle/src/middle/resolve_lifetime.rs
@@ -6,7 +6,6 @@
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::ItemLocalId;
 use rustc_macros::HashStable;
-use rustc_span::symbol::Symbol;
 
 #[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Debug, HashStable)]
 pub enum Region {
@@ -17,20 +16,6 @@
     Free(DefId, /* lifetime decl */ DefId),
 }
 
-/// This is used in diagnostics to improve suggestions for missing generic arguments.
-/// It gives information on the type of lifetimes that are in scope for a particular `PathSegment`,
-/// so that we can e.g. suggest elided-lifetimes-in-paths of the form <'_, '_> e.g.
-#[derive(Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Debug, HashStable)]
-pub enum LifetimeScopeForPath {
-    // Contains all lifetime names that are in scope and could possibly be used in generics
-    // arguments of path.
-    NonElided(Vec<Symbol>),
-
-    // Information that allows us to suggest args of the form `<'_>` in case
-    // no generic arguments were provided for a path.
-    Elided,
-}
-
 /// A set containing, at most, one known element.
 /// If two distinct values are inserted into a set, then it
 /// becomes `Many`, which can be used to detect ambiguities.
diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs
index 6918046..d23707a 100644
--- a/compiler/rustc_middle/src/middle/stability.rs
+++ b/compiler/rustc_middle/src/middle/stability.rs
@@ -9,10 +9,9 @@
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::{Applicability, Diagnostic};
 use rustc_feature::GateIssue;
-use rustc_hir as hir;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, LocalDefId};
-use rustc_hir::{self, HirId};
+use rustc_hir::{self as hir, HirId};
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_session::lint::builtin::{DEPRECATED, DEPRECATED_IN_FUTURE, SOFT_UNSTABLE};
 use rustc_session::lint::{BuiltinLintDiagnostics, Level, Lint, LintBuffer};
@@ -29,7 +28,7 @@
 }
 
 /// An entry in the `depr_map`.
-#[derive(Copy, Clone, HashStable, Debug)]
+#[derive(Copy, Clone, HashStable, Debug, Encodable, Decodable)]
 pub struct DeprecationEntry {
     /// The metadata of the attribute associated with this entry.
     pub attr: Deprecation,
@@ -154,7 +153,7 @@
         diag.span_suggestion(
             span,
             &format!("replace the use of the deprecated {}", kind),
-            suggestion.to_string(),
+            suggestion,
             Applicability::MachineApplicable,
         );
     }
@@ -306,6 +305,14 @@
     None
 }
 
+/// An override option for eval_stability.
+pub enum AllowUnstable {
+    /// Don't emit an unstable error for the item
+    Yes,
+    /// Handle the item normally
+    No,
+}
+
 impl<'tcx> TyCtxt<'tcx> {
     /// Evaluates the stability of an item.
     ///
@@ -323,6 +330,28 @@
         span: Span,
         method_span: Option<Span>,
     ) -> EvalResult {
+        self.eval_stability_allow_unstable(def_id, id, span, method_span, AllowUnstable::No)
+    }
+
+    /// Evaluates the stability of an item.
+    ///
+    /// Returns `EvalResult::Allow` if the item is stable, or unstable but the corresponding
+    /// `#![feature]` has been provided. Returns `EvalResult::Deny` which describes the offending
+    /// unstable feature otherwise.
+    ///
+    /// If `id` is `Some(_)`, this function will also check if the item at `def_id` has been
+    /// deprecated. If the item is indeed deprecated, we will emit a deprecation lint attached to
+    /// `id`.
+    ///
+    /// Pass `AllowUnstable::Yes` to `allow_unstable` to force an unstable item to be allowed. Deprecation warnings will be emitted normally.
+    pub fn eval_stability_allow_unstable(
+        self,
+        def_id: DefId,
+        id: Option<HirId>,
+        span: Span,
+        method_span: Option<Span>,
+        allow_unstable: AllowUnstable,
+    ) -> EvalResult {
         // Deprecated attributes apply in-crate and cross-crate.
         if let Some(id) = id {
             if let Some(depr_entry) = self.lookup_deprecation_entry(def_id) {
@@ -419,6 +448,10 @@
                     }
                 }
 
+                if matches!(allow_unstable, AllowUnstable::Yes) {
+                    return EvalResult::Allow;
+                }
+
                 let suggestion = suggestion_for_allocator_api(self, def_id, span, feature);
                 EvalResult::Deny { feature, reason, issue, suggestion, is_soft }
             }
@@ -445,11 +478,38 @@
         span: Span,
         method_span: Option<Span>,
     ) {
-        self.check_optional_stability(def_id, id, span, method_span, |span, def_id| {
-            // The API could be uncallable for other reasons, for example when a private module
-            // was referenced.
-            self.sess.delay_span_bug(span, &format!("encountered unmarked API: {:?}", def_id));
-        })
+        self.check_stability_allow_unstable(def_id, id, span, method_span, AllowUnstable::No)
+    }
+
+    /// Checks if an item is stable or error out.
+    ///
+    /// If the item defined by `def_id` is unstable and the corresponding `#![feature]` does not
+    /// exist, emits an error.
+    ///
+    /// This function will also check if the item is deprecated.
+    /// If so, and `id` is not `None`, a deprecated lint attached to `id` will be emitted.
+    ///
+    /// Pass `AllowUnstable::Yes` to `allow_unstable` to force an unstable item to be allowed. Deprecation warnings will be emitted normally.
+    pub fn check_stability_allow_unstable(
+        self,
+        def_id: DefId,
+        id: Option<HirId>,
+        span: Span,
+        method_span: Option<Span>,
+        allow_unstable: AllowUnstable,
+    ) {
+        self.check_optional_stability(
+            def_id,
+            id,
+            span,
+            method_span,
+            allow_unstable,
+            |span, def_id| {
+                // The API could be uncallable for other reasons, for example when a private module
+                // was referenced.
+                self.sess.delay_span_bug(span, &format!("encountered unmarked API: {:?}", def_id));
+            },
+        )
     }
 
     /// Like `check_stability`, except that we permit items to have custom behaviour for
@@ -462,6 +522,7 @@
         id: Option<HirId>,
         span: Span,
         method_span: Option<Span>,
+        allow_unstable: AllowUnstable,
         unmarked: impl FnOnce(Span, DefId),
     ) {
         let soft_handler = |lint, span, msg: &_| {
@@ -469,7 +530,7 @@
                 lint.build(msg).emit();
             })
         };
-        match self.eval_stability(def_id, id, span, method_span) {
+        match self.eval_stability_allow_unstable(def_id, id, span, method_span, allow_unstable) {
             EvalResult::Allow => {}
             EvalResult::Deny { feature, reason, issue, suggestion, is_soft } => report_unstable(
                 self.sess,
diff --git a/compiler/rustc_middle/src/mir/generic_graph.rs b/compiler/rustc_middle/src/mir/generic_graph.rs
index dbebed6..a4d7891 100644
--- a/compiler/rustc_middle/src/mir/generic_graph.rs
+++ b/compiler/rustc_middle/src/mir/generic_graph.rs
@@ -24,7 +24,7 @@
         let terminator = body[source].terminator();
         let labels = terminator.kind.fmt_successor_labels();
 
-        for (&target, label) in terminator.successors().zip(labels) {
+        for (target, label) in terminator.successors().zip(labels) {
             let src = node(def_id, source);
             let trg = node(def_id, target);
             edges.push(Edge::new(src, trg, label.to_string()));
diff --git a/compiler/rustc_middle/src/mir/graph_cyclic_cache.rs b/compiler/rustc_middle/src/mir/graph_cyclic_cache.rs
index e2f3d6e..1279f5a 100644
--- a/compiler/rustc_middle/src/mir/graph_cyclic_cache.rs
+++ b/compiler/rustc_middle/src/mir/graph_cyclic_cache.rs
@@ -3,7 +3,7 @@
 };
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_data_structures::sync::OnceCell;
-use rustc_serialize as serialize;
+use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
 
 /// Helper type to cache the result of `graph::is_cyclic`.
 #[derive(Clone, Debug)]
@@ -36,17 +36,17 @@
     }
 }
 
-impl<S: serialize::Encoder> serialize::Encodable<S> for GraphIsCyclicCache {
+impl<S: Encoder> Encodable<S> for GraphIsCyclicCache {
     #[inline]
-    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
-        serialize::Encodable::encode(&(), s)
+    fn encode(&self, s: &mut S) {
+        Encodable::encode(&(), s);
     }
 }
 
-impl<D: serialize::Decoder> serialize::Decodable<D> for GraphIsCyclicCache {
+impl<D: Decoder> Decodable<D> for GraphIsCyclicCache {
     #[inline]
     fn decode(d: &mut D) -> Self {
-        let () = serialize::Decodable::decode(d);
+        let () = Decodable::decode(d);
         Self::new()
     }
 }
diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs
index 5564852..10c4ea6 100644
--- a/compiler/rustc_middle/src/mir/interpret/allocation.rs
+++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs
@@ -3,6 +3,7 @@
 use std::borrow::Cow;
 use std::convert::{TryFrom, TryInto};
 use std::fmt;
+use std::hash;
 use std::iter;
 use std::ops::{Deref, Range};
 use std::ptr;
@@ -25,7 +26,9 @@
 /// Its public API is rather low-level, working directly with allocation offsets and a custom error
 /// type to account for the lack of an AllocId on this level. The Miri/CTFE core engine `memory`
 /// module provides higher-level access.
-#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)]
+// Note: for performance reasons when interning, some of the `Allocation` fields can be partially
+// hashed. (see the `Hash` impl below for more details), so the impl is not derived.
+#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable)]
 #[derive(HashStable)]
 pub struct Allocation<Tag = AllocId, Extra = ()> {
     /// The actual bytes of the allocation.
@@ -49,6 +52,46 @@
     pub extra: Extra,
 }
 
+/// This is the maximum size we will hash at a time, when interning an `Allocation` and its
+/// `InitMask`. Note, we hash that amount of bytes twice: at the start, and at the end of a buffer.
+/// Used when these two structures are large: we only partially hash the larger fields in that
+/// situation. See the comment at the top of their respective `Hash` impl for more details.
+const MAX_BYTES_TO_HASH: usize = 64;
+
+/// This is the maximum size (in bytes) for which a buffer will be fully hashed, when interning.
+/// Otherwise, it will be partially hashed in 2 slices, requiring at least 2 `MAX_BYTES_TO_HASH`
+/// bytes.
+const MAX_HASHED_BUFFER_LEN: usize = 2 * MAX_BYTES_TO_HASH;
+
+// Const allocations are only hashed for interning. However, they can be large, making the hashing
+// expensive especially since it uses `FxHash`: it's better suited to short keys, not potentially
+// big buffers like the actual bytes of allocation. We can partially hash some fields when they're
+// large.
+impl hash::Hash for Allocation {
+    fn hash<H: hash::Hasher>(&self, state: &mut H) {
+        // Partially hash the `bytes` buffer when it is large. To limit collisions with common
+        // prefixes and suffixes, we hash the length and some slices of the buffer.
+        let byte_count = self.bytes.len();
+        if byte_count > MAX_HASHED_BUFFER_LEN {
+            // Hash the buffer's length.
+            byte_count.hash(state);
+
+            // And its head and tail.
+            self.bytes[..MAX_BYTES_TO_HASH].hash(state);
+            self.bytes[byte_count - MAX_BYTES_TO_HASH..].hash(state);
+        } else {
+            self.bytes.hash(state);
+        }
+
+        // Hash the other fields as usual.
+        self.relocations.hash(state);
+        self.init_mask.hash(state);
+        self.align.hash(state);
+        self.mutability.hash(state);
+        self.extra.hash(state);
+    }
+}
+
 /// Interned types generally have an `Outer` type and an `Inner` type, where
 /// `Outer` is a newtype around `Interned<Inner>`, and all the operations are
 /// done on `Outer`, because all occurrences are interned. E.g. `Ty` is an
@@ -171,7 +214,7 @@
 
     /// Try to create an Allocation of `size` bytes, failing if there is not enough memory
     /// available to the compiler to do so.
-    pub fn uninit(size: Size, align: Align, panic_on_fail: bool) -> InterpResult<'static, Self> {
+    pub fn uninit<'tcx>(size: Size, align: Align, panic_on_fail: bool) -> InterpResult<'tcx, Self> {
         let bytes = Box::<[u8]>::try_new_zeroed_slice(size.bytes_usize()).map_err(|_| {
             // This results in an error that can happen non-deterministically, since the memory
             // available to the compiler can change between runs. Normally queries are always
@@ -201,12 +244,12 @@
 
 impl Allocation {
     /// Convert Tag and add Extra fields
-    pub fn convert_tag_add_extra<Tag, Extra>(
+    pub fn convert_tag_add_extra<Tag, Extra, Err>(
         self,
         cx: &impl HasDataLayout,
         extra: Extra,
-        mut tagger: impl FnMut(Pointer<AllocId>) -> Pointer<Tag>,
-    ) -> Allocation<Tag, Extra> {
+        mut tagger: impl FnMut(Pointer<AllocId>) -> Result<Pointer<Tag>, Err>,
+    ) -> Result<Allocation<Tag, Extra>, Err> {
         // Compute new pointer tags, which also adjusts the bytes.
         let mut bytes = self.bytes;
         let mut new_relocations = Vec::with_capacity(self.relocations.0.len());
@@ -217,19 +260,19 @@
             let ptr_bytes = &mut bytes[idx..idx + ptr_size];
             let bits = read_target_uint(endian, ptr_bytes).unwrap();
             let (ptr_tag, ptr_offset) =
-                tagger(Pointer::new(alloc_id, Size::from_bytes(bits))).into_parts();
+                tagger(Pointer::new(alloc_id, Size::from_bytes(bits)))?.into_parts();
             write_target_uint(endian, ptr_bytes, ptr_offset.bytes().into()).unwrap();
             new_relocations.push((offset, ptr_tag));
         }
         // Create allocation.
-        Allocation {
+        Ok(Allocation {
             bytes,
             relocations: Relocations::from_presorted(new_relocations),
             init_mask: self.init_mask,
             align: self.align,
             mutability: self.mutability,
             extra,
-        }
+        })
     }
 }
 
@@ -264,9 +307,18 @@
 
 /// Byte accessors.
 impl<Tag: Provenance, Extra> Allocation<Tag, Extra> {
-    /// The last argument controls whether we error out when there are uninitialized
-    /// or pointer bytes. You should never call this, call `get_bytes` or
-    /// `get_bytes_with_uninit_and_ptr` instead,
+    /// This is the entirely abstraction-violating way to just grab the raw bytes without
+    /// caring about relocations. It just deduplicates some code between `read_scalar`
+    /// and `get_bytes_internal`.
+    fn get_bytes_even_more_internal(&self, range: AllocRange) -> &[u8] {
+        &self.bytes[range.start.bytes_usize()..range.end().bytes_usize()]
+    }
+
+    /// The last argument controls whether we error out when there are uninitialized or pointer
+    /// bytes. However, we *always* error when there are relocations overlapping the edges of the
+    /// range.
+    ///
+    /// You should never call this, call `get_bytes` or `get_bytes_with_uninit_and_ptr` instead,
     ///
     /// This function also guarantees that the resulting pointer will remain stable
     /// even when new allocations are pushed to the `HashMap`. `mem_copy_repeatedly` relies
@@ -287,7 +339,7 @@
             self.check_relocation_edges(cx, range)?;
         }
 
-        Ok(&self.bytes[range.start.bytes_usize()..range.end().bytes_usize()])
+        Ok(self.get_bytes_even_more_internal(range))
     }
 
     /// Checks that these bytes are initialized and not pointer bytes, and then return them
@@ -350,19 +402,22 @@
 /// Reading and writing.
 impl<Tag: Provenance, Extra> Allocation<Tag, Extra> {
     /// Validates that `ptr.offset` and `ptr.offset + size` do not point to the middle of a
-    /// relocation. If `allow_uninit_and_ptr` is `false`, also enforces that the memory in the
-    /// given range contains neither relocations nor uninitialized bytes.
+    /// relocation. If `allow_uninit`/`allow_ptr` is `false`, also enforces that the memory in the
+    /// given range contains no uninitialized bytes/relocations.
     pub fn check_bytes(
         &self,
         cx: &impl HasDataLayout,
         range: AllocRange,
-        allow_uninit_and_ptr: bool,
+        allow_uninit: bool,
+        allow_ptr: bool,
     ) -> AllocResult {
         // Check bounds and relocations on the edges.
         self.get_bytes_with_uninit_and_ptr(cx, range)?;
         // Check uninit and ptr.
-        if !allow_uninit_and_ptr {
+        if !allow_uninit {
             self.check_init(range)?;
+        }
+        if !allow_ptr {
             self.check_relocations(cx, range)?;
         }
         Ok(())
@@ -370,6 +425,9 @@
 
     /// Reads a *non-ZST* scalar.
     ///
+    /// If `read_provenance` is `true`, this will also read provenance; otherwise (if the machine
+    /// supports that) provenance is entirely ignored.
+    ///
     /// ZSTs can't be read because in order to obtain a `Pointer`, we need to check
     /// for ZSTness anyway due to integer pointers being valid for ZSTs.
     ///
@@ -379,35 +437,47 @@
         &self,
         cx: &impl HasDataLayout,
         range: AllocRange,
+        read_provenance: bool,
     ) -> AllocResult<ScalarMaybeUninit<Tag>> {
-        // `get_bytes_with_uninit_and_ptr` tests relocation edges.
-        // We deliberately error when loading data that partially has provenance, or partially
-        // initialized data (that's the check below), into a scalar. The LLVM semantics of this are
-        // unclear so we are conservative. See <https://github.com/rust-lang/rust/issues/69488> for
-        // further discussion.
-        let bytes = self.get_bytes_with_uninit_and_ptr(cx, range)?;
-        // Uninit check happens *after* we established that the alignment is correct.
-        // We must not return `Ok()` for unaligned pointers!
+        if read_provenance {
+            assert_eq!(range.size, cx.data_layout().pointer_size);
+        }
+
+        // First and foremost, if anything is uninit, bail.
         if self.is_init(range).is_err() {
             // This inflates uninitialized bytes to the entire scalar, even if only a few
             // bytes are uninitialized.
             return Ok(ScalarMaybeUninit::Uninit);
         }
-        // Now we do the actual reading.
-        let bits = read_target_uint(cx.data_layout().endian, bytes).unwrap();
-        // See if we got a pointer.
-        if range.size != cx.data_layout().pointer_size {
-            // Not a pointer.
-            // *Now*, we better make sure that the inside is free of relocations too.
-            self.check_relocations(cx, range)?;
-        } else {
-            // Maybe a pointer.
-            if let Some(&prov) = self.relocations.get(&range.start) {
-                let ptr = Pointer::new(prov, Size::from_bytes(bits));
-                return Ok(ScalarMaybeUninit::from_pointer(ptr, cx));
-            }
+
+        // If we are doing a pointer read, and there is a relocation exactly where we
+        // are reading, then we can put data and relocation back together and return that.
+        if read_provenance && let Some(&prov) = self.relocations.get(&range.start) {
+            // We already checked init and relocations, so we can use this function.
+            let bytes = self.get_bytes_even_more_internal(range);
+            let bits = read_target_uint(cx.data_layout().endian, bytes).unwrap();
+            let ptr = Pointer::new(prov, Size::from_bytes(bits));
+            return Ok(ScalarMaybeUninit::from_pointer(ptr, cx));
         }
-        // We don't. Just return the bits.
+
+        // If we are *not* reading a pointer, and we can just ignore relocations,
+        // then do exactly that.
+        if !read_provenance && Tag::OFFSET_IS_ADDR {
+            // We just strip provenance.
+            let bytes = self.get_bytes_even_more_internal(range);
+            let bits = read_target_uint(cx.data_layout().endian, bytes).unwrap();
+            return Ok(ScalarMaybeUninit::Scalar(Scalar::from_uint(bits, range.size)));
+        }
+
+        // It's complicated. Better make sure there is no provenance anywhere.
+        // FIXME: If !OFFSET_IS_ADDR, this is the best we can do. But if OFFSET_IS_ADDR, then
+        // `read_pointer` is true and we ideally would distinguish the following two cases:
+        // - The entire `range` is covered by 2 relocations for the same provenance.
+        //   Then we should return a pointer with that provenance.
+        // - The range has inhomogeneous provenance. Then we should return just the
+        //   underlying bits.
+        let bytes = self.get_bytes(cx, range)?;
+        let bits = read_target_uint(cx.data_layout().endian, bytes).unwrap();
         Ok(ScalarMaybeUninit::Scalar(Scalar::from_uint(bits, range.size)))
     }
 
@@ -510,8 +580,9 @@
         let start = range.start;
         let end = range.end();
 
-        // We need to handle clearing the relocations from parts of a pointer. See
-        // <https://github.com/rust-lang/rust/issues/87184> for details.
+        // We need to handle clearing the relocations from parts of a pointer.
+        // FIXME: Miri should preserve partial relocations; see
+        // https://github.com/rust-lang/miri/issues/2181.
         if first < start {
             if Tag::ERR_ON_PARTIAL_PTR_OVERWRITE {
                 return Err(AllocError::PartialPointerOverwrite(first));
@@ -637,13 +708,43 @@
 
 /// A bitmask where each bit refers to the byte with the same index. If the bit is `true`, the byte
 /// is initialized. If it is `false` the byte is uninitialized.
-#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)]
+// Note: for performance reasons when interning, some of the `InitMask` fields can be partially
+// hashed. (see the `Hash` impl below for more details), so the impl is not derived.
+#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable)]
 #[derive(HashStable)]
 pub struct InitMask {
     blocks: Vec<Block>,
     len: Size,
 }
 
+// Const allocations are only hashed for interning. However, they can be large, making the hashing
+// expensive especially since it uses `FxHash`: it's better suited to short keys, not potentially
+// big buffers like the allocation's init mask. We can partially hash some fields when they're
+// large.
+impl hash::Hash for InitMask {
+    fn hash<H: hash::Hasher>(&self, state: &mut H) {
+        const MAX_BLOCKS_TO_HASH: usize = MAX_BYTES_TO_HASH / std::mem::size_of::<Block>();
+        const MAX_BLOCKS_LEN: usize = MAX_HASHED_BUFFER_LEN / std::mem::size_of::<Block>();
+
+        // Partially hash the `blocks` buffer when it is large. To limit collisions with common
+        // prefixes and suffixes, we hash the length and some slices of the buffer.
+        let block_count = self.blocks.len();
+        if block_count > MAX_BLOCKS_LEN {
+            // Hash the buffer's length.
+            block_count.hash(state);
+
+            // And its head and tail.
+            self.blocks[..MAX_BLOCKS_TO_HASH].hash(state);
+            self.blocks[block_count - MAX_BLOCKS_TO_HASH..].hash(state);
+        } else {
+            self.blocks.hash(state);
+        }
+
+        // Hash the other fields as usual.
+        self.len.hash(state);
+    }
+}
+
 impl InitMask {
     pub const BLOCK_SIZE: u64 = 64;
 
diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs
index 9afe952..65de64c 100644
--- a/compiler/rustc_middle/src/mir/interpret/error.rs
+++ b/compiler/rustc_middle/src/mir/interpret/error.rs
@@ -1,7 +1,7 @@
 use super::{AllocId, ConstAlloc, Pointer, Scalar};
 
 use crate::mir::interpret::ConstValue;
-use crate::ty::{layout, query::TyCtxtAt, tls, FnSig, Ty};
+use crate::ty::{layout, query::TyCtxtAt, tls, FnSig, Ty, ValTree};
 
 use rustc_data_structures::sync::Lock;
 use rustc_errors::{pluralize, struct_span_err, DiagnosticBuilder, ErrorGuaranteed};
@@ -35,6 +35,7 @@
 
 pub type EvalToAllocationRawResult<'tcx> = Result<ConstAlloc<'tcx>, ErrorHandled>;
 pub type EvalToConstValueResult<'tcx> = Result<ConstValue<'tcx>, ErrorHandled>;
+pub type EvalToValTreeResult<'tcx> = Result<Option<ValTree<'tcx>>, ErrorHandled>;
 
 pub fn struct_error<'tcx>(
     tcx: TyCtxtAt<'tcx>,
@@ -148,8 +149,6 @@
     /// (which unfortunately typeck does not reject).
     /// Not using `FnAbiError` as that contains a nested `LayoutError`.
     FnAbiAdjustForForeignAbi(call::AdjustForForeignAbiError),
-    /// An invalid transmute happened.
-    TransmuteSizeDiff(Ty<'tcx>, Ty<'tcx>),
     /// SizeOf of unsized type was requested.
     SizeOfUnsizedType(Ty<'tcx>),
 }
@@ -165,11 +164,6 @@
             }
             Layout(ref err) => write!(f, "{}", err),
             FnAbiAdjustForForeignAbi(ref err) => write!(f, "{}", err),
-            TransmuteSizeDiff(from_ty, to_ty) => write!(
-                f,
-                "transmuting `{}` to `{}` is not possible, because these types do not have the same size",
-                from_ty, to_ty
-            ),
             SizeOfUnsizedType(ty) => write!(f, "size_of called on unsized type `{}`", ty),
         }
     }
@@ -434,7 +428,7 @@
     /// Encountered a pointer where we needed raw bytes.
     ReadPointerAsBytes,
     /// Overwriting parts of a pointer; the resulting state cannot be represented in our
-    /// `Allocation` data structure.
+    /// `Allocation` data structure. See <https://github.com/rust-lang/miri/issues/2181>.
     PartialPointerOverwrite(Pointer<AllocId>),
     //
     // The variants below are only reachable from CTFE/const prop, miri will never emit them.
diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs
index d8cba39..8733a85 100644
--- a/compiler/rustc_middle/src/mir/interpret/mod.rs
+++ b/compiler/rustc_middle/src/mir/interpret/mod.rs
@@ -56,7 +56,7 @@
 // In the `throw_*` macros, avoid `return` to make them work with `try {}`.
 #[macro_export]
 macro_rules! throw_unsup {
-    ($($tt:tt)*) => { Err::<!, _>(err_unsup!($($tt)*))? };
+    ($($tt:tt)*) => { do yeet err_unsup!($($tt)*) };
 }
 
 #[macro_export]
@@ -66,12 +66,12 @@
 
 #[macro_export]
 macro_rules! throw_inval {
-    ($($tt:tt)*) => { Err::<!, _>(err_inval!($($tt)*))? };
+    ($($tt:tt)*) => { do yeet err_inval!($($tt)*) };
 }
 
 #[macro_export]
 macro_rules! throw_ub {
-    ($($tt:tt)*) => { Err::<!, _>(err_ub!($($tt)*))? };
+    ($($tt:tt)*) => { do yeet err_ub!($($tt)*) };
 }
 
 #[macro_export]
@@ -81,12 +81,12 @@
 
 #[macro_export]
 macro_rules! throw_exhaust {
-    ($($tt:tt)*) => { Err::<!, _>(err_exhaust!($($tt)*))? };
+    ($($tt:tt)*) => { do yeet err_exhaust!($($tt)*) };
 }
 
 #[macro_export]
 macro_rules! throw_machine_stop {
-    ($($tt:tt)*) => { Err::<!, _>(err_machine_stop!($($tt)*))? };
+    ($($tt:tt)*) => { do yeet err_machine_stop!($($tt)*) };
 }
 
 mod allocation;
@@ -119,9 +119,9 @@
 
 pub use self::error::{
     struct_error, CheckInAllocMsg, ErrorHandled, EvalToAllocationRawResult, EvalToConstValueResult,
-    InterpError, InterpErrorInfo, InterpResult, InvalidProgramInfo, MachineStopType,
-    ResourceExhaustionInfo, ScalarSizeMismatch, UndefinedBehaviorInfo, UninitBytesAccess,
-    UnsupportedOpInfo,
+    EvalToValTreeResult, InterpError, InterpErrorInfo, InterpResult, InvalidProgramInfo,
+    MachineStopType, ResourceExhaustionInfo, ScalarSizeMismatch, UndefinedBehaviorInfo,
+    UninitBytesAccess, UnsupportedOpInfo,
 };
 
 pub use self::value::{get_slice_bytes, ConstAlloc, ConstValue, Scalar, ScalarMaybeUninit};
@@ -203,31 +203,30 @@
     Static,
 }
 
-pub fn specialized_encode_alloc_id<'tcx, E: TyEncoder<'tcx>>(
+pub fn specialized_encode_alloc_id<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>>(
     encoder: &mut E,
     tcx: TyCtxt<'tcx>,
     alloc_id: AllocId,
-) -> Result<(), E::Error> {
+) {
     match tcx.global_alloc(alloc_id) {
         GlobalAlloc::Memory(alloc) => {
             trace!("encoding {:?} with {:#?}", alloc_id, alloc);
-            AllocDiscriminant::Alloc.encode(encoder)?;
-            alloc.encode(encoder)?;
+            AllocDiscriminant::Alloc.encode(encoder);
+            alloc.encode(encoder);
         }
         GlobalAlloc::Function(fn_instance) => {
             trace!("encoding {:?} with {:#?}", alloc_id, fn_instance);
-            AllocDiscriminant::Fn.encode(encoder)?;
-            fn_instance.encode(encoder)?;
+            AllocDiscriminant::Fn.encode(encoder);
+            fn_instance.encode(encoder);
         }
         GlobalAlloc::Static(did) => {
             assert!(!tcx.is_thread_local_static(did));
             // References to statics doesn't need to know about their allocations,
             // just about its `DefId`.
-            AllocDiscriminant::Static.encode(encoder)?;
-            did.encode(encoder)?;
+            AllocDiscriminant::Static.encode(encoder);
+            did.encode(encoder);
         }
     }
-    Ok(())
 }
 
 // Used to avoid infinite recursion when decoding cyclic allocations.
@@ -277,7 +276,7 @@
     /// Decodes an `AllocId` in a thread-safe way.
     pub fn decode_alloc_id<'tcx, D>(&self, decoder: &mut D) -> AllocId
     where
-        D: TyDecoder<'tcx>,
+        D: TyDecoder<I = TyCtxt<'tcx>>,
     {
         // Read the index of the allocation.
         let idx = usize::try_from(decoder.read_u32()).unwrap();
@@ -305,7 +304,7 @@
                         AllocDiscriminant::Alloc => {
                             // If this is an allocation, we need to reserve an
                             // `AllocId` so we can decode cyclic graphs.
-                            let alloc_id = decoder.tcx().reserve_alloc_id();
+                            let alloc_id = decoder.interner().reserve_alloc_id();
                             *entry =
                                 State::InProgress(TinyList::new_single(self.session_id), alloc_id);
                             Some(alloc_id)
@@ -349,7 +348,7 @@
                     // We already have a reserved `AllocId`.
                     let alloc_id = alloc_id.unwrap();
                     trace!("decoded alloc {:?}: {:#?}", alloc_id, alloc);
-                    decoder.tcx().set_alloc_id_same_memory(alloc_id, alloc);
+                    decoder.interner().set_alloc_id_same_memory(alloc_id, alloc);
                     alloc_id
                 }
                 AllocDiscriminant::Fn => {
@@ -357,7 +356,7 @@
                     trace!("creating fn alloc ID");
                     let instance = ty::Instance::decode(decoder);
                     trace!("decoded fn alloc instance: {:?}", instance);
-                    let alloc_id = decoder.tcx().create_fn_alloc(instance);
+                    let alloc_id = decoder.interner().create_fn_alloc(instance);
                     alloc_id
                 }
                 AllocDiscriminant::Static => {
@@ -365,7 +364,7 @@
                     trace!("creating extern static alloc ID");
                     let did = <DefId as Decodable<D>>::decode(decoder);
                     trace!("decoded static def-ID: {:?}", did);
-                    let alloc_id = decoder.tcx().create_static_alloc(did);
+                    let alloc_id = decoder.interner().create_static_alloc(did);
                     alloc_id
                 }
             }
@@ -414,7 +413,7 @@
     }
 }
 
-crate struct AllocMap<'tcx> {
+pub(crate) struct AllocMap<'tcx> {
     /// Maps `AllocId`s to their corresponding allocations.
     alloc_map: FxHashMap<AllocId, GlobalAlloc<'tcx>>,
 
@@ -430,7 +429,7 @@
 }
 
 impl<'tcx> AllocMap<'tcx> {
-    crate fn new() -> Self {
+    pub(crate) fn new() -> Self {
         AllocMap {
             alloc_map: Default::default(),
             dedup: Default::default(),
diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs
index 7e5989b..4895b53 100644
--- a/compiler/rustc_middle/src/mir/interpret/queries.rs
+++ b/compiler/rustc_middle/src/mir/interpret/queries.rs
@@ -1,16 +1,17 @@
-use super::{ErrorHandled, EvalToConstValueResult, GlobalId};
+use super::{ErrorHandled, EvalToConstValueResult, EvalToValTreeResult, GlobalId};
 
 use crate::mir;
 use crate::ty::fold::TypeFoldable;
 use crate::ty::subst::InternalSubsts;
-use crate::ty::{self, TyCtxt};
+use crate::ty::{self, query::TyCtxtAt, query::TyCtxtEnsure, TyCtxt};
 use rustc_hir::def_id::DefId;
-use rustc_span::Span;
+use rustc_span::{Span, DUMMY_SP};
 
 impl<'tcx> TyCtxt<'tcx> {
     /// Evaluates a constant without providing any substitutions. This is useful to evaluate consts
     /// that can't take any generic arguments like statics, const items or enum discriminants. If a
     /// generic parameter is used within the constant `ErrorHandled::ToGeneric` will be returned.
+    #[instrument(skip(self), level = "debug")]
     pub fn const_eval_poly(self, def_id: DefId) -> EvalToConstValueResult<'tcx> {
         // In some situations def_id will have substitutions within scope, but they aren't allowed
         // to be used. So we can't use `Instance::mono`, instead we feed unresolved substitutions
@@ -22,7 +23,6 @@
         let param_env = self.param_env(def_id).with_reveal_all_normalized(self);
         self.const_eval_global_id(param_env, cid, None)
     }
-
     /// Resolves and evaluates a constant.
     ///
     /// The constant can be located on a trait like `<A as B>::C`, in which case the given
@@ -59,6 +59,33 @@
         }
     }
 
+    #[instrument(level = "debug", skip(self))]
+    pub fn const_eval_resolve_for_typeck(
+        self,
+        param_env: ty::ParamEnv<'tcx>,
+        ct: ty::Unevaluated<'tcx>,
+        span: Option<Span>,
+    ) -> EvalToValTreeResult<'tcx> {
+        // Cannot resolve `Unevaluated` constants that contain inference
+        // variables. We reject those here since `resolve_opt_const_arg`
+        // would fail otherwise.
+        //
+        // When trying to evaluate constants containing inference variables,
+        // use `Infcx::const_eval_resolve` instead.
+        if ct.substs.has_infer_types_or_consts() {
+            bug!("did not expect inference variables here");
+        }
+
+        match ty::Instance::resolve_opt_const_arg(self, param_env, ct.def, ct.substs) {
+            Ok(Some(instance)) => {
+                let cid = GlobalId { instance, promoted: ct.promoted };
+                self.const_eval_global_id_for_typeck(param_env, cid, span)
+            }
+            Ok(None) => Err(ErrorHandled::TooGeneric),
+            Err(error_reported) => Err(ErrorHandled::Reported(error_reported)),
+        }
+    }
+
     pub fn const_eval_instance(
         self,
         param_env: ty::ParamEnv<'tcx>,
@@ -68,7 +95,8 @@
         self.const_eval_global_id(param_env, GlobalId { instance, promoted: None }, span)
     }
 
-    /// Evaluate a constant.
+    /// Evaluate a constant to a `ConstValue`.
+    #[instrument(skip(self), level = "debug")]
     pub fn const_eval_global_id(
         self,
         param_env: ty::ParamEnv<'tcx>,
@@ -86,6 +114,38 @@
         }
     }
 
+    /// Evaluate a constant to a type-level constant.
+    #[instrument(skip(self), level = "debug")]
+    pub fn const_eval_global_id_for_typeck(
+        self,
+        param_env: ty::ParamEnv<'tcx>,
+        cid: GlobalId<'tcx>,
+        span: Option<Span>,
+    ) -> EvalToValTreeResult<'tcx> {
+        let param_env = param_env.with_const();
+        debug!(?param_env);
+        // Const-eval shouldn't depend on lifetimes at all, so we can erase them, which should
+        // improve caching of queries.
+        let inputs = self.erase_regions(param_env.and(cid));
+        debug!(?inputs);
+        if let Some(span) = span {
+            self.at(span).eval_to_valtree(inputs)
+        } else {
+            self.eval_to_valtree(inputs)
+        }
+    }
+
+    /// Evaluate a static's initializer, returning the allocation of the initializer's memory.
+    #[inline(always)]
+    pub fn eval_static_initializer(
+        self,
+        def_id: DefId,
+    ) -> Result<mir::ConstAllocation<'tcx>, ErrorHandled> {
+        self.at(DUMMY_SP).eval_static_initializer(def_id)
+    }
+}
+
+impl<'tcx> TyCtxtAt<'tcx> {
     /// Evaluate a static's initializer, returning the allocation of the initializer's memory.
     pub fn eval_static_initializer(
         self,
@@ -93,7 +153,7 @@
     ) -> Result<mir::ConstAllocation<'tcx>, ErrorHandled> {
         trace!("eval_static_initializer: Need to compute {:?}", def_id);
         assert!(self.is_static(def_id));
-        let instance = ty::Instance::mono(self, def_id);
+        let instance = ty::Instance::mono(*self, def_id);
         let gid = GlobalId { instance, promoted: None };
         self.eval_to_allocation(gid, ty::ParamEnv::reveal_all())
     }
@@ -109,12 +169,55 @@
         let raw_const = self.eval_to_allocation_raw(param_env.and(gid))?;
         Ok(self.global_alloc(raw_const.alloc_id).unwrap_memory())
     }
+}
 
-    /// Destructure a constant ADT or array into its variant index and its field values.
-    pub fn destructure_const(
+impl<'tcx> TyCtxtEnsure<'tcx> {
+    /// Evaluates a constant without providing any substitutions. This is useful to evaluate consts
+    /// that can't take any generic arguments like statics, const items or enum discriminants. If a
+    /// generic parameter is used within the constant `ErrorHandled::ToGeneric` will be returned.
+    #[instrument(skip(self), level = "debug")]
+    pub fn const_eval_poly(self, def_id: DefId) {
+        // In some situations def_id will have substitutions within scope, but they aren't allowed
+        // to be used. So we can't use `Instance::mono`, instead we feed unresolved substitutions
+        // into `const_eval` which will return `ErrorHandled::ToGeneric` if any of them are
+        // encountered.
+        let substs = InternalSubsts::identity_for_item(self.tcx, def_id);
+        let instance = ty::Instance::new(def_id, substs);
+        let cid = GlobalId { instance, promoted: None };
+        let param_env =
+            self.tcx.param_env(def_id).with_reveal_all_normalized(self.tcx).with_const();
+        // Const-eval shouldn't depend on lifetimes at all, so we can erase them, which should
+        // improve caching of queries.
+        let inputs = self.tcx.erase_regions(param_env.and(cid));
+        self.eval_to_const_value_raw(inputs)
+    }
+
+    /// Evaluate a static's initializer, returning the allocation of the initializer's memory.
+    pub fn eval_static_initializer(self, def_id: DefId) {
+        trace!("eval_static_initializer: Need to compute {:?}", def_id);
+        assert!(self.tcx.is_static(def_id));
+        let instance = ty::Instance::mono(self.tcx, def_id);
+        let gid = GlobalId { instance, promoted: None };
+        let param_env = ty::ParamEnv::reveal_all().with_const();
+        trace!("eval_to_allocation: Need to compute {:?}", gid);
+        self.eval_to_allocation_raw(param_env.and(gid))
+    }
+}
+
+impl<'tcx> TyCtxt<'tcx> {
+    /// Destructure a type-level constant ADT or array into its variant index and its field values.
+    /// Panics if the destructuring fails, use `try_destructure_const` for fallible version.
+    pub fn destructure_const(self, const_: ty::Const<'tcx>) -> ty::DestructuredConst<'tcx> {
+        self.try_destructure_const(const_).unwrap()
+    }
+
+    /// Destructure a mir constant ADT or array into its variant index and its field values.
+    /// Panics if the destructuring fails, use `try_destructure_const` for fallible version.
+    pub fn destructure_mir_constant(
         self,
-        param_env_and_val: ty::ParamEnvAnd<'tcx, ty::Const<'tcx>>,
-    ) -> mir::DestructuredConst<'tcx> {
-        self.try_destructure_const(param_env_and_val).unwrap()
+        param_env: ty::ParamEnv<'tcx>,
+        constant: mir::ConstantKind<'tcx>,
+    ) -> mir::DestructuredMirConstant<'tcx> {
+        self.try_destructure_mir_constant(param_env.and(constant)).unwrap()
     }
 }
diff --git a/compiler/rustc_middle/src/mir/interpret/value.rs b/compiler/rustc_middle/src/mir/interpret/value.rs
index eeee170..e80918d 100644
--- a/compiler/rustc_middle/src/mir/interpret/value.rs
+++ b/compiler/rustc_middle/src/mir/interpret/value.rs
@@ -111,6 +111,10 @@
     pub fn from_machine_usize(i: u64, cx: &impl HasDataLayout) -> Self {
         ConstValue::Scalar(Scalar::from_machine_usize(i, cx))
     }
+
+    pub fn zst() -> Self {
+        Self::Scalar(Scalar::ZST)
+    }
 }
 
 /// A `Scalar` represents an immediate, primitive value existing outside of a
@@ -315,7 +319,7 @@
                 ScalarSizeMismatch { target_size: target_size.bytes(), data_size: size.bytes() }
             })?),
             Scalar::Ptr(ptr, sz) => {
-                if target_size.bytes() != sz.into() {
+                if target_size.bytes() != u64::from(sz) {
                     return Err(ScalarSizeMismatch {
                         target_size: target_size.bytes(),
                         data_size: sz.into(),
@@ -397,38 +401,38 @@
     /// Converts the scalar to produce an unsigned integer of the given size.
     /// Fails if the scalar is a pointer.
     #[inline]
-    pub fn to_uint(self, size: Size) -> InterpResult<'static, u128> {
+    pub fn to_uint(self, size: Size) -> InterpResult<'tcx, u128> {
         self.to_bits(size)
     }
 
     /// Converts the scalar to produce a `u8`. Fails if the scalar is a pointer.
-    pub fn to_u8(self) -> InterpResult<'static, u8> {
+    pub fn to_u8(self) -> InterpResult<'tcx, u8> {
         self.to_uint(Size::from_bits(8)).map(|v| u8::try_from(v).unwrap())
     }
 
     /// Converts the scalar to produce a `u16`. Fails if the scalar is a pointer.
-    pub fn to_u16(self) -> InterpResult<'static, u16> {
+    pub fn to_u16(self) -> InterpResult<'tcx, u16> {
         self.to_uint(Size::from_bits(16)).map(|v| u16::try_from(v).unwrap())
     }
 
     /// Converts the scalar to produce a `u32`. Fails if the scalar is a pointer.
-    pub fn to_u32(self) -> InterpResult<'static, u32> {
+    pub fn to_u32(self) -> InterpResult<'tcx, u32> {
         self.to_uint(Size::from_bits(32)).map(|v| u32::try_from(v).unwrap())
     }
 
     /// Converts the scalar to produce a `u64`. Fails if the scalar is a pointer.
-    pub fn to_u64(self) -> InterpResult<'static, u64> {
+    pub fn to_u64(self) -> InterpResult<'tcx, u64> {
         self.to_uint(Size::from_bits(64)).map(|v| u64::try_from(v).unwrap())
     }
 
     /// Converts the scalar to produce a `u128`. Fails if the scalar is a pointer.
-    pub fn to_u128(self) -> InterpResult<'static, u128> {
+    pub fn to_u128(self) -> InterpResult<'tcx, u128> {
         self.to_uint(Size::from_bits(128))
     }
 
     /// Converts the scalar to produce a machine-pointer-sized unsigned integer.
     /// Fails if the scalar is a pointer.
-    pub fn to_machine_usize(self, cx: &impl HasDataLayout) -> InterpResult<'static, u64> {
+    pub fn to_machine_usize(self, cx: &impl HasDataLayout) -> InterpResult<'tcx, u64> {
         let b = self.to_uint(cx.data_layout().pointer_size)?;
         Ok(u64::try_from(b).unwrap())
     }
@@ -436,51 +440,51 @@
     /// Converts the scalar to produce a signed integer of the given size.
     /// Fails if the scalar is a pointer.
     #[inline]
-    pub fn to_int(self, size: Size) -> InterpResult<'static, i128> {
+    pub fn to_int(self, size: Size) -> InterpResult<'tcx, i128> {
         let b = self.to_bits(size)?;
         Ok(size.sign_extend(b) as i128)
     }
 
     /// Converts the scalar to produce an `i8`. Fails if the scalar is a pointer.
-    pub fn to_i8(self) -> InterpResult<'static, i8> {
+    pub fn to_i8(self) -> InterpResult<'tcx, i8> {
         self.to_int(Size::from_bits(8)).map(|v| i8::try_from(v).unwrap())
     }
 
     /// Converts the scalar to produce an `i16`. Fails if the scalar is a pointer.
-    pub fn to_i16(self) -> InterpResult<'static, i16> {
+    pub fn to_i16(self) -> InterpResult<'tcx, i16> {
         self.to_int(Size::from_bits(16)).map(|v| i16::try_from(v).unwrap())
     }
 
     /// Converts the scalar to produce an `i32`. Fails if the scalar is a pointer.
-    pub fn to_i32(self) -> InterpResult<'static, i32> {
+    pub fn to_i32(self) -> InterpResult<'tcx, i32> {
         self.to_int(Size::from_bits(32)).map(|v| i32::try_from(v).unwrap())
     }
 
     /// Converts the scalar to produce an `i64`. Fails if the scalar is a pointer.
-    pub fn to_i64(self) -> InterpResult<'static, i64> {
+    pub fn to_i64(self) -> InterpResult<'tcx, i64> {
         self.to_int(Size::from_bits(64)).map(|v| i64::try_from(v).unwrap())
     }
 
     /// Converts the scalar to produce an `i128`. Fails if the scalar is a pointer.
-    pub fn to_i128(self) -> InterpResult<'static, i128> {
+    pub fn to_i128(self) -> InterpResult<'tcx, i128> {
         self.to_int(Size::from_bits(128))
     }
 
     /// Converts the scalar to produce a machine-pointer-sized signed integer.
     /// Fails if the scalar is a pointer.
-    pub fn to_machine_isize(self, cx: &impl HasDataLayout) -> InterpResult<'static, i64> {
+    pub fn to_machine_isize(self, cx: &impl HasDataLayout) -> InterpResult<'tcx, i64> {
         let b = self.to_int(cx.data_layout().pointer_size)?;
         Ok(i64::try_from(b).unwrap())
     }
 
     #[inline]
-    pub fn to_f32(self) -> InterpResult<'static, Single> {
+    pub fn to_f32(self) -> InterpResult<'tcx, Single> {
         // Going through `u32` to check size and truncation.
         Ok(Single::from_bits(self.to_u32()?.into()))
     }
 
     #[inline]
-    pub fn to_f64(self) -> InterpResult<'static, Double> {
+    pub fn to_f64(self) -> InterpResult<'tcx, Double> {
         // Going through `u64` to check size and truncation.
         Ok(Double::from_bits(self.to_u64()?.into()))
     }
@@ -534,7 +538,7 @@
     }
 
     #[inline]
-    pub fn check_init(self) -> InterpResult<'static, Scalar<Tag>> {
+    pub fn check_init<'tcx>(self) -> InterpResult<'tcx, Scalar<Tag>> {
         match self {
             ScalarMaybeUninit::Scalar(scalar) => Ok(scalar),
             ScalarMaybeUninit::Uninit => throw_ub!(InvalidUninitBytes(None)),
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index af18ada..3f5b16d 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -3,16 +3,19 @@
 //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/mir/index.html
 
 use crate::mir::coverage::{CodeRegion, CoverageKind};
-use crate::mir::interpret::{ConstAllocation, ConstValue, GlobalAlloc, Scalar};
+use crate::mir::interpret::{
+    AllocRange, ConstAllocation, ConstValue, GlobalAlloc, LitToConstInput, Scalar,
+};
 use crate::mir::visit::MirVisitable;
 use crate::ty::adjustment::PointerCast;
 use crate::ty::codec::{TyDecoder, TyEncoder};
-use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeVisitor};
+use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable, TypeVisitor};
 use crate::ty::print::{FmtPrinter, Printer};
 use crate::ty::subst::{GenericArg, InternalSubsts, Subst, SubstsRef};
 use crate::ty::{self, List, Ty, TyCtxt};
 use crate::ty::{AdtDef, InstanceDef, Region, ScalarInt, UserTypeAnnotationIndex};
 
+use rustc_data_structures::captures::Captures;
 use rustc_errors::ErrorGuaranteed;
 use rustc_hir::def::{CtorKind, Namespace};
 use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID};
@@ -171,12 +174,14 @@
     /// terminator means that the auto-generated drop glue will be invoked. Also, `Copy` operands
     /// are allowed for non-`Copy` types.
     DropsLowered = 3,
+    /// After this projections may only contain deref projections as the first element.
+    Derefered = 4,
     /// Beginning with this phase, the following variant is disallowed:
     /// * [`Rvalue::Aggregate`] for any `AggregateKind` except `Array`
     ///
     /// And the following variant is allowed:
     /// * [`StatementKind::SetDiscriminant`]
-    Deaggregated = 4,
+    Deaggregated = 5,
     /// Before this phase, generators are in the "source code" form, featuring `yield` statements
     /// and such. With this phase change, they are transformed into a proper state machine. Running
     /// optimizations before this change can be potentially dangerous because the source code is to
@@ -189,9 +194,10 @@
     ///
     /// Beginning with this phase, the following variants are disallowed:
     /// * [`TerminatorKind::Yield`](terminator::TerminatorKind::Yield)
-    /// * [`TerminatorKind::GeneratorDrop](terminator::TerminatorKind::GeneratorDrop)
-    GeneratorsLowered = 5,
-    Optimized = 6,
+    /// * [`TerminatorKind::GeneratorDrop`](terminator::TerminatorKind::GeneratorDrop)
+    /// * [`ProjectionElem::Deref`] of `Box`
+    GeneratorsLowered = 6,
+    Optimized = 7,
 }
 
 impl MirPhase {
@@ -484,7 +490,7 @@
 
     /// Returns an iterator over all user-declared mutable locals.
     #[inline]
-    pub fn mut_vars_iter<'a>(&'a self) -> impl Iterator<Item = Local> + 'a {
+    pub fn mut_vars_iter<'a>(&'a self) -> impl Iterator<Item = Local> + Captures<'tcx> + 'a {
         (self.arg_count + 1..self.local_decls.len()).filter_map(move |index| {
             let local = Local::new(index);
             let decl = &self.local_decls[local];
@@ -498,7 +504,9 @@
 
     /// Returns an iterator over all user-declared mutable arguments and locals.
     #[inline]
-    pub fn mut_vars_and_args_iter<'a>(&'a self) -> impl Iterator<Item = Local> + 'a {
+    pub fn mut_vars_and_args_iter<'a>(
+        &'a self,
+    ) -> impl Iterator<Item = Local> + Captures<'tcx> + 'a {
         (1..self.local_decls.len()).filter_map(move |index| {
             let local = Local::new(index);
             let decl = &self.local_decls[local];
@@ -665,23 +673,23 @@
 const TAG_CLEAR_CROSS_CRATE_CLEAR: u8 = 0;
 const TAG_CLEAR_CROSS_CRATE_SET: u8 = 1;
 
-impl<'tcx, E: TyEncoder<'tcx>, T: Encodable<E>> Encodable<E> for ClearCrossCrate<T> {
+impl<E: TyEncoder, T: Encodable<E>> Encodable<E> for ClearCrossCrate<T> {
     #[inline]
-    fn encode(&self, e: &mut E) -> Result<(), E::Error> {
+    fn encode(&self, e: &mut E) {
         if E::CLEAR_CROSS_CRATE {
-            return Ok(());
+            return;
         }
 
         match *self {
             ClearCrossCrate::Clear => TAG_CLEAR_CROSS_CRATE_CLEAR.encode(e),
             ClearCrossCrate::Set(ref val) => {
-                TAG_CLEAR_CROSS_CRATE_SET.encode(e)?;
-                val.encode(e)
+                TAG_CLEAR_CROSS_CRATE_SET.encode(e);
+                val.encode(e);
             }
         }
     }
 }
-impl<'tcx, D: TyDecoder<'tcx>, T: Decodable<D>> Decodable<D> for ClearCrossCrate<T> {
+impl<D: TyDecoder, T: Decodable<D>> Decodable<D> for ClearCrossCrate<T> {
     #[inline]
     fn decode(d: &mut D) -> ClearCrossCrate<T> {
         if D::CLEAR_CROSS_CRATE {
@@ -1355,10 +1363,7 @@
 /// Type for MIR `Assert` terminator error messages.
 pub type AssertMessage<'tcx> = AssertKind<Operand<'tcx>>;
 
-// FIXME: Change `Successors` to `impl Iterator<Item = BasicBlock>`.
-#[allow(rustc::pass_by_value)]
-pub type Successors<'a> =
-    iter::Chain<option::IntoIter<&'a BasicBlock>, slice::Iter<'a, BasicBlock>>;
+pub type Successors<'a> = impl Iterator<Item = BasicBlock> + 'a;
 pub type SuccessorsMut<'a> =
     iter::Chain<option::IntoIter<&'a mut BasicBlock>, slice::IterMut<'a, BasicBlock>>;
 
@@ -2140,10 +2145,7 @@
     pub fn iter_projections(
         self,
     ) -> impl Iterator<Item = (PlaceRef<'tcx>, PlaceElem<'tcx>)> + DoubleEndedIterator {
-        self.projection.iter().enumerate().map(move |(i, proj)| {
-            let base = PlaceRef { local: self.local, projection: &self.projection[..i] };
-            (base, proj)
-        })
+        self.as_ref().iter_projections()
     }
 
     /// Generates a new place by appending `more_projections` to the existing ones
@@ -2203,6 +2205,23 @@
             None
         }
     }
+
+    /// Iterate over the projections in evaluation order, i.e., the first element is the base with
+    /// its projection and then subsequently more projections are added.
+    /// As a concrete example, given the place a.b.c, this would yield:
+    /// - (a, .b)
+    /// - (a.b, .c)
+    ///
+    /// Given a place without projections, the iterator is empty.
+    #[inline]
+    pub fn iter_projections(
+        self,
+    ) -> impl Iterator<Item = (PlaceRef<'tcx>, PlaceElem<'tcx>)> + DoubleEndedIterator {
+        self.projection.iter().enumerate().map(move |(i, proj)| {
+            let base = PlaceRef { local: self.local, projection: &self.projection[..i] };
+            (base, *proj)
+        })
+    }
 }
 
 impl Debug for Place<'_> {
@@ -2397,7 +2416,7 @@
         Operand::Constant(Box::new(Constant {
             span,
             user_ty: None,
-            literal: ConstantKind::Ty(ty::Const::zero_sized(tcx, ty)),
+            literal: ConstantKind::Val(ConstValue::zst(), ty),
         }))
     }
 
@@ -2602,10 +2621,52 @@
 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
 static_assert_size!(Rvalue<'_>, 40);
 
+impl<'tcx> Rvalue<'tcx> {
+    /// Returns true if rvalue can be safely removed when the result is unused.
+    #[inline]
+    pub fn is_safe_to_remove(&self) -> bool {
+        match self {
+            // Pointer to int casts may be side-effects due to exposing the provenance.
+            // While the model is undecided, we should be conservative. See
+            // <https://www.ralfj.de/blog/2022/04/11/provenance-exposed.html>
+            Rvalue::Cast(CastKind::PointerExposeAddress, _, _) => false,
+
+            Rvalue::Use(_)
+            | Rvalue::Repeat(_, _)
+            | Rvalue::Ref(_, _, _)
+            | Rvalue::ThreadLocalRef(_)
+            | Rvalue::AddressOf(_, _)
+            | Rvalue::Len(_)
+            | Rvalue::Cast(
+                CastKind::Misc | CastKind::Pointer(_) | CastKind::PointerFromExposedAddress,
+                _,
+                _,
+            )
+            | Rvalue::BinaryOp(_, _)
+            | Rvalue::CheckedBinaryOp(_, _)
+            | Rvalue::NullaryOp(_, _)
+            | Rvalue::UnaryOp(_, _)
+            | Rvalue::Discriminant(_)
+            | Rvalue::Aggregate(_, _)
+            | Rvalue::ShallowInitBox(_, _) => true,
+        }
+    }
+}
+
 #[derive(Clone, Copy, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)]
 pub enum CastKind {
-    Misc,
+    /// An exposing pointer to address cast. A cast between a pointer and an integer type, or
+    /// between a function pointer and an integer type.
+    /// See the docs on `expose_addr` for more details.
+    PointerExposeAddress,
+    /// An address-to-pointer cast that picks up an exposed provenance.
+    /// See the docs on `from_exposed_addr` for more details.
+    PointerFromExposedAddress,
+    /// All sorts of pointer-to-pointer casts. Note that reference-to-raw-ptr casts are
+    /// translated into `&raw mut/const *r`, i.e., they are not actually casts.
     Pointer(PointerCast),
+    /// Remaining unclassified casts.
+    Misc,
 }
 
 #[derive(Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)]
@@ -2909,22 +2970,9 @@
     }
 }
 
-impl<'tcx> From<ty::Const<'tcx>> for ConstantKind<'tcx> {
-    #[inline]
-    fn from(ct: ty::Const<'tcx>) -> Self {
-        match ct.val() {
-            ty::ConstKind::Value(cv) => {
-                // FIXME Once valtrees are introduced we need to convert those
-                // into `ConstValue` instances here
-                Self::Val(cv, ct.ty())
-            }
-            _ => Self::Ty(ct),
-        }
-    }
-}
-
 impl<'tcx> ConstantKind<'tcx> {
     /// Returns `None` if the constant is not trivially safe for use in the type system.
+    #[inline]
     pub fn const_for_ty(&self) -> Option<ty::Const<'tcx>> {
         match self {
             ConstantKind::Ty(c) => Some(*c),
@@ -2932,6 +2980,7 @@
         }
     }
 
+    #[inline(always)]
     pub fn ty(&self) -> Ty<'tcx> {
         match self {
             ConstantKind::Ty(c) => c.ty(),
@@ -2939,32 +2988,34 @@
         }
     }
 
-    pub fn try_val(&self) -> Option<ConstValue<'tcx>> {
+    #[inline]
+    pub fn try_to_value(self, tcx: TyCtxt<'tcx>) -> Option<interpret::ConstValue<'tcx>> {
         match self {
-            ConstantKind::Ty(c) => match c.val() {
-                ty::ConstKind::Value(v) => Some(v),
+            ConstantKind::Ty(c) => match c.kind() {
+                ty::ConstKind::Value(valtree) => Some(tcx.valtree_to_const_val((c.ty(), valtree))),
                 _ => None,
             },
-            ConstantKind::Val(v, _) => Some(*v),
-        }
-    }
-
-    #[inline]
-    pub fn try_to_value(self) -> Option<interpret::ConstValue<'tcx>> {
-        match self {
-            ConstantKind::Ty(c) => c.val().try_to_value(),
             ConstantKind::Val(val, _) => Some(val),
         }
     }
 
     #[inline]
     pub fn try_to_scalar(self) -> Option<Scalar> {
-        self.try_to_value()?.try_to_scalar()
+        match self {
+            ConstantKind::Ty(c) => match c.kind() {
+                ty::ConstKind::Value(valtree) => match valtree {
+                    ty::ValTree::Leaf(scalar_int) => Some(Scalar::Int(scalar_int)),
+                    ty::ValTree::Branch(_) => None,
+                },
+                _ => None,
+            },
+            ConstantKind::Val(val, _) => val.try_to_scalar(),
+        }
     }
 
     #[inline]
     pub fn try_to_scalar_int(self) -> Option<ScalarInt> {
-        Some(self.try_to_value()?.try_to_scalar()?.assert_int())
+        Some(self.try_to_scalar()?.assert_int())
     }
 
     #[inline]
@@ -2981,9 +3032,7 @@
     pub fn eval(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Self {
         match self {
             Self::Ty(c) => {
-                // FIXME Need to use a different evaluation function that directly returns a `ConstValue`
-                // if evaluation succeeds and does not create a ValTree first
-                if let Some(val) = c.val().try_eval(tcx, param_env) {
+                if let Some(val) = c.kind().try_eval_for_mir(tcx, param_env) {
                     match val {
                         Ok(val) => Self::Val(val, c.ty()),
                         Err(_) => Self::Ty(tcx.const_error(self.ty())),
@@ -3037,6 +3086,11 @@
         }
     }
 
+    #[inline]
+    pub fn from_value(val: ConstValue<'tcx>, ty: Ty<'tcx>) -> Self {
+        Self::Val(val, ty)
+    }
+
     pub fn from_bits(
         tcx: TyCtxt<'tcx>,
         bits: u128,
@@ -3053,11 +3107,13 @@
         Self::Val(cv, param_env_ty.value)
     }
 
+    #[inline]
     pub fn from_bool(tcx: TyCtxt<'tcx>, v: bool) -> Self {
         let cv = ConstValue::from_bool(v);
         Self::Val(cv, tcx.types.bool)
     }
 
+    #[inline]
     pub fn zero_sized(ty: Ty<'tcx>) -> Self {
         let cv = ConstValue::Scalar(Scalar::ZST);
         Self::Val(cv, ty)
@@ -3068,6 +3124,12 @@
         Self::from_bits(tcx, n as u128, ty::ParamEnv::empty().and(ty))
     }
 
+    #[inline]
+    pub fn from_scalar(_tcx: TyCtxt<'tcx>, s: Scalar, ty: Ty<'tcx>) -> Self {
+        let val = ConstValue::Scalar(s);
+        Self::Val(val, ty)
+    }
+
     /// Literals are converted to `ConstantKindVal`, const generic parameters are eagerly
     /// converted to a constant, everything else becomes `Unevaluated`.
     pub fn from_anon_const(
@@ -3079,6 +3141,58 @@
     }
 
     #[instrument(skip(tcx), level = "debug")]
+    pub fn from_inline_const(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self {
+        let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
+        let body_id = match tcx.hir().get(hir_id) {
+            hir::Node::AnonConst(ac) => ac.body,
+            _ => span_bug!(
+                tcx.def_span(def_id.to_def_id()),
+                "from_inline_const can only process anonymous constants"
+            ),
+        };
+        let expr = &tcx.hir().body(body_id).value;
+        let ty = tcx.typeck(def_id).node_type(hir_id);
+
+        let lit_input = match expr.kind {
+            hir::ExprKind::Lit(ref lit) => Some(LitToConstInput { lit: &lit.node, ty, neg: false }),
+            hir::ExprKind::Unary(hir::UnOp::Neg, ref expr) => match expr.kind {
+                hir::ExprKind::Lit(ref lit) => {
+                    Some(LitToConstInput { lit: &lit.node, ty, neg: true })
+                }
+                _ => None,
+            },
+            _ => None,
+        };
+        if let Some(lit_input) = lit_input {
+            // If an error occurred, ignore that it's a literal and leave reporting the error up to
+            // mir.
+            match tcx.at(expr.span).lit_to_mir_constant(lit_input) {
+                Ok(c) => return c,
+                Err(_) => {}
+            }
+        }
+
+        let typeck_root_def_id = tcx.typeck_root_def_id(def_id.to_def_id());
+        let parent_substs =
+            tcx.erase_regions(InternalSubsts::identity_for_item(tcx, typeck_root_def_id));
+        let substs =
+            ty::InlineConstSubsts::new(tcx, ty::InlineConstSubstsParts { parent_substs, ty })
+                .substs;
+        let uneval_const = tcx.mk_const(ty::ConstS {
+            kind: ty::ConstKind::Unevaluated(ty::Unevaluated {
+                def: ty::WithOptConstParam::unknown(def_id).to_global(),
+                substs,
+                promoted: None,
+            }),
+            ty,
+        });
+        debug!(?uneval_const);
+        debug_assert!(!uneval_const.has_free_regions());
+
+        Self::Ty(uneval_const)
+    }
+
+    #[instrument(skip(tcx), level = "debug")]
     fn from_opt_const_arg_anon_const(
         tcx: TyCtxt<'tcx>,
         def: ty::WithOptConstParam<LocalDefId>,
@@ -3103,8 +3217,10 @@
             }
             _ => expr,
         };
+        debug!("expr.kind: {:?}", expr.kind);
 
         let ty = tcx.type_of(def.def_id_for_type_of());
+        debug!(?ty);
 
         // FIXME(const_generics): We currently have to special case parameters because `min_const_generics`
         // does not provide the parents generics to anonymous constants. We still allow generic const
@@ -3125,9 +3241,10 @@
                 let index = generics.param_def_id_to_index[&def_id];
                 let name = tcx.hir().name(hir_id);
                 let ty_const = tcx.mk_const(ty::ConstS {
-                    val: ty::ConstKind::Param(ty::ParamConst::new(index, name)),
+                    kind: ty::ConstKind::Param(ty::ParamConst::new(index, name)),
                     ty,
                 });
+                debug!(?ty_const);
 
                 return Self::Ty(ty_const);
             }
@@ -3157,23 +3274,38 @@
         debug!(?span, ?param_env);
 
         match tcx.const_eval_resolve(param_env, uneval, Some(span)) {
-            Ok(val) => Self::Val(val, ty),
+            Ok(val) => {
+                debug!("evaluated const value: {:?}", val);
+                Self::Val(val, ty)
+            }
             Err(_) => {
+                debug!("error encountered during evaluation");
                 // Error was handled in `const_eval_resolve`. Here we just create a
                 // new unevaluated const and error hard later in codegen
                 let ty_const = tcx.mk_const(ty::ConstS {
-                    val: ty::ConstKind::Unevaluated(ty::Unevaluated {
+                    kind: ty::ConstKind::Unevaluated(ty::Unevaluated {
                         def: def.to_global(),
                         substs: InternalSubsts::identity_for_item(tcx, def.did.to_def_id()),
                         promoted: None,
                     }),
                     ty,
                 });
+                debug!(?ty_const);
 
                 Self::Ty(ty_const)
             }
         }
     }
+
+    pub fn from_const(c: ty::Const<'tcx>, tcx: TyCtxt<'tcx>) -> Self {
+        match c.kind() {
+            ty::ConstKind::Value(valtree) => {
+                let const_val = tcx.valtree_to_const_val((c.ty(), valtree));
+                Self::Val(const_val, c.ty())
+            }
+            _ => Self::Ty(c),
+        }
+    }
 }
 
 /// A collection of projections into user types.
@@ -3328,20 +3460,14 @@
 TrivialTypeFoldableAndLiftImpls! { ProjectionKind, }
 
 impl<'tcx> TypeFoldable<'tcx> for UserTypeProjection {
-    fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
-        self,
-        folder: &mut F,
-    ) -> Result<Self, F::Error> {
+    fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
         Ok(UserTypeProjection {
             base: self.base.try_fold_with(folder)?,
             projs: self.projs.try_fold_with(folder)?,
         })
     }
 
-    fn super_visit_with<Vs: TypeVisitor<'tcx>>(
-        &self,
-        visitor: &mut Vs,
-    ) -> ControlFlow<Vs::BreakTy> {
+    fn visit_with<Vs: TypeVisitor<'tcx>>(&self, visitor: &mut Vs) -> ControlFlow<Vs::BreakTy> {
         self.base.visit_with(visitor)
         // Note: there's nothing in `self.proj` to visit.
     }
@@ -3395,20 +3521,183 @@
     })
 }
 
+fn pretty_print_byte_str(fmt: &mut Formatter<'_>, byte_str: &[u8]) -> fmt::Result {
+    fmt.write_str("b\"")?;
+    for &c in byte_str {
+        for e in std::ascii::escape_default(c) {
+            fmt.write_char(e as char)?;
+        }
+    }
+    fmt.write_str("\"")?;
+
+    Ok(())
+}
+
+fn comma_sep<'tcx>(fmt: &mut Formatter<'_>, elems: Vec<ConstantKind<'tcx>>) -> fmt::Result {
+    let mut first = true;
+    for elem in elems {
+        if !first {
+            fmt.write_str(", ")?;
+        }
+        fmt.write_str(&format!("{}", elem))?;
+        first = false;
+    }
+    Ok(())
+}
+
+// FIXME: Move that into `mir/pretty.rs`.
 fn pretty_print_const_value<'tcx>(
-    val: interpret::ConstValue<'tcx>,
+    ct: ConstValue<'tcx>,
     ty: Ty<'tcx>,
     fmt: &mut Formatter<'_>,
-    print_types: bool,
+    print_ty: bool,
 ) -> fmt::Result {
     use crate::ty::print::PrettyPrinter;
+
     ty::tls::with(|tcx| {
-        let val = tcx.lift(val).unwrap();
+        let ct = tcx.lift(ct).unwrap();
         let ty = tcx.lift(ty).unwrap();
-        let mut cx = FmtPrinter::new(tcx, Namespace::ValueNS);
-        cx.print_alloc_ids = true;
-        let cx = cx.pretty_print_const_value(val, ty, print_types)?;
-        fmt.write_str(&cx.into_buffer())?;
+
+        if tcx.sess.verbose() {
+            fmt.write_str(&format!("ConstValue({:?}: {})", ct, ty))?;
+            return Ok(());
+        }
+
+        let u8_type = tcx.types.u8;
+        match (ct, ty.kind()) {
+            // Byte/string slices, printed as (byte) string literals.
+            (ConstValue::Slice { data, start, end }, ty::Ref(_, inner, _)) => {
+                match inner.kind() {
+                    ty::Slice(t) => {
+                        if *t == u8_type {
+                            // The `inspect` here is okay since we checked the bounds, and there are
+                            // no relocations (we have an active slice reference here). We don't use
+                            // this result to affect interpreter execution.
+                            let byte_str = data
+                                .inner()
+                                .inspect_with_uninit_and_ptr_outside_interpreter(start..end);
+                            pretty_print_byte_str(fmt, byte_str)?;
+                            return Ok(());
+                        }
+                    }
+                    ty::Str => {
+                        // The `inspect` here is okay since we checked the bounds, and there are no
+                        // relocations (we have an active `str` reference here). We don't use this
+                        // result to affect interpreter execution.
+                        let slice = data
+                            .inner()
+                            .inspect_with_uninit_and_ptr_outside_interpreter(start..end);
+                        fmt.write_str(&format!("{:?}", String::from_utf8_lossy(slice)))?;
+                        return Ok(());
+                    }
+                    _ => {}
+                }
+            }
+            (ConstValue::ByRef { alloc, offset }, ty::Array(t, n)) if *t == u8_type => {
+                let n = n.kind().try_to_bits(tcx.data_layout.pointer_size).unwrap();
+                // cast is ok because we already checked for pointer size (32 or 64 bit) above
+                let range = AllocRange { start: offset, size: Size::from_bytes(n) };
+                let byte_str = alloc.inner().get_bytes(&tcx, range).unwrap();
+                fmt.write_str("*")?;
+                pretty_print_byte_str(fmt, byte_str)?;
+                return Ok(());
+            }
+            // Aggregates, printed as array/tuple/struct/variant construction syntax.
+            //
+            // NB: the `has_param_types_or_consts` check ensures that we can use
+            // the `destructure_const` query with an empty `ty::ParamEnv` without
+            // introducing ICEs (e.g. via `layout_of`) from missing bounds.
+            // E.g. `transmute([0usize; 2]): (u8, *mut T)` needs to know `T: Sized`
+            // to be able to destructure the tuple into `(0u8, *mut T)
+            //
+            // FIXME(eddyb) for `--emit=mir`/`-Z dump-mir`, we should provide the
+            // correct `ty::ParamEnv` to allow printing *all* constant values.
+            (_, ty::Array(..) | ty::Tuple(..) | ty::Adt(..)) if !ty.has_param_types_or_consts() => {
+                let ct = tcx.lift(ct).unwrap();
+                let ty = tcx.lift(ty).unwrap();
+                if let Some(contents) = tcx.try_destructure_mir_constant(
+                    ty::ParamEnv::reveal_all().and(ConstantKind::Val(ct, ty)),
+                ) {
+                    let fields = contents.fields.iter().copied().collect::<Vec<_>>();
+                    match *ty.kind() {
+                        ty::Array(..) => {
+                            fmt.write_str("[")?;
+                            comma_sep(fmt, fields)?;
+                            fmt.write_str("]")?;
+                        }
+                        ty::Tuple(..) => {
+                            fmt.write_str("(")?;
+                            comma_sep(fmt, fields)?;
+                            if contents.fields.len() == 1 {
+                                fmt.write_str(",")?;
+                            }
+                            fmt.write_str(")")?;
+                        }
+                        ty::Adt(def, _) if def.variants().is_empty() => {
+                            fmt.write_str(&format!("{{unreachable(): {}}}", ty))?;
+                        }
+                        ty::Adt(def, substs) => {
+                            let variant_idx = contents
+                                .variant
+                                .expect("destructed mir constant of adt without variant idx");
+                            let variant_def = &def.variant(variant_idx);
+                            let substs = tcx.lift(substs).unwrap();
+                            let mut cx = FmtPrinter::new(tcx, Namespace::ValueNS);
+                            cx.print_alloc_ids = true;
+                            let cx = cx.print_value_path(variant_def.def_id, substs)?;
+                            fmt.write_str(&cx.into_buffer())?;
+
+                            match variant_def.ctor_kind {
+                                CtorKind::Const => {}
+                                CtorKind::Fn => {
+                                    fmt.write_str("(")?;
+                                    comma_sep(fmt, fields)?;
+                                    fmt.write_str(")")?;
+                                }
+                                CtorKind::Fictive => {
+                                    fmt.write_str(" {{ ")?;
+                                    let mut first = true;
+                                    for (field_def, field) in iter::zip(&variant_def.fields, fields)
+                                    {
+                                        if !first {
+                                            fmt.write_str(", ")?;
+                                        }
+                                        fmt.write_str(&format!("{}: {}", field_def.name, field))?;
+                                        first = false;
+                                    }
+                                    fmt.write_str(" }}")?;
+                                }
+                            }
+                        }
+                        _ => unreachable!(),
+                    }
+                    return Ok(());
+                } else {
+                    // Fall back to debug pretty printing for invalid constants.
+                    fmt.write_str(&format!("{:?}", ct))?;
+                    if print_ty {
+                        fmt.write_str(&format!(": {}", ty))?;
+                    }
+                    return Ok(());
+                };
+            }
+            (ConstValue::Scalar(scalar), _) => {
+                let mut cx = FmtPrinter::new(tcx, Namespace::ValueNS);
+                cx.print_alloc_ids = true;
+                let ty = tcx.lift(ty).unwrap();
+                cx = cx.pretty_print_const_scalar(scalar, ty, print_ty)?;
+                fmt.write_str(&cx.into_buffer())?;
+                return Ok(());
+            }
+            // FIXME(oli-obk): also pretty print arrays and other aggregate constants by reading
+            // their fields instead of just dumping the memory.
+            _ => {}
+        }
+        // fallback
+        fmt.write_str(&format!("{:?}", ct))?;
+        if print_ty {
+            fmt.write_str(&format!(": {}", ty))?;
+        }
         Ok(())
     })
 }
@@ -3434,13 +3723,13 @@
 impl<'tcx> graph::WithSuccessors for Body<'tcx> {
     #[inline]
     fn successors(&self, node: Self::Node) -> <Self as GraphSuccessors<'_>>::Iter {
-        self.basic_blocks[node].terminator().successors().cloned()
+        self.basic_blocks[node].terminator().successors()
     }
 }
 
 impl<'a, 'b> graph::GraphSuccessors<'b> for Body<'a> {
     type Item = BasicBlock;
-    type Iter = iter::Cloned<Successors<'b>>;
+    type Iter = Successors<'b>;
 }
 
 impl<'tcx, 'graph> graph::GraphPredecessors<'graph> for Body<'tcx> {
diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs
index d389fa8..021f278 100644
--- a/compiler/rustc_middle/src/mir/mono.rs
+++ b/compiler/rustc_middle/src/mir/mono.rs
@@ -336,7 +336,7 @@
         WorkProductId::from_cgu_name(self.name().as_str())
     }
 
-    pub fn work_product(&self, tcx: TyCtxt<'_>) -> WorkProduct {
+    pub fn previous_work_product(&self, tcx: TyCtxt<'_>) -> WorkProduct {
         let work_product_id = self.work_product_id();
         tcx.dep_graph
             .previous_work_product(&work_product_id)
diff --git a/compiler/rustc_middle/src/mir/patch.rs b/compiler/rustc_middle/src/mir/patch.rs
index d03f923..c1e1cfe 100644
--- a/compiler/rustc_middle/src/mir/patch.rs
+++ b/compiler/rustc_middle/src/mir/patch.rs
@@ -166,11 +166,8 @@
             // get terminator's targets and apply the statement to all of them.
             if loc.statement_index > body[loc.block].statements.len() {
                 let term = body[loc.block].terminator();
-                let successors = term.successors().clone();
-
-                for i in successors {
-                    stmts_and_targets
-                        .push((Statement { source_info, kind: stmt.clone() }, i.clone()));
+                for i in term.successors() {
+                    stmts_and_targets.push((Statement { source_info, kind: stmt.clone() }, i));
                 }
                 delta += 1;
                 continue;
@@ -194,7 +191,7 @@
         }
     }
 
-    pub fn source_info_for_location(&self, body: &Body<'_>, loc: Location) -> SourceInfo {
+    pub fn source_info_for_location(&self, body: &Body<'tcx>, loc: Location) -> SourceInfo {
         let data = match loc.block.index().checked_sub(body.basic_blocks().len()) {
             Some(new) => &self.new_blocks[new],
             None => &body[loc.block],
diff --git a/compiler/rustc_middle/src/mir/predecessors.rs b/compiler/rustc_middle/src/mir/predecessors.rs
index 4fe2cde..620cf7e 100644
--- a/compiler/rustc_middle/src/mir/predecessors.rs
+++ b/compiler/rustc_middle/src/mir/predecessors.rs
@@ -3,7 +3,7 @@
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_data_structures::sync::OnceCell;
 use rustc_index::vec::IndexVec;
-use rustc_serialize as serialize;
+use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
 use smallvec::SmallVec;
 
 use crate::mir::{BasicBlock, BasicBlockData};
@@ -43,7 +43,7 @@
             let mut preds = IndexVec::from_elem(SmallVec::new(), basic_blocks);
             for (bb, data) in basic_blocks.iter_enumerated() {
                 if let Some(term) = &data.terminator {
-                    for &succ in term.successors() {
+                    for succ in term.successors() {
                         preds[succ].push(bb);
                     }
                 }
@@ -54,14 +54,12 @@
     }
 }
 
-impl<S: serialize::Encoder> serialize::Encodable<S> for PredecessorCache {
+impl<S: Encoder> Encodable<S> for PredecessorCache {
     #[inline]
-    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
-        s.emit_unit()
-    }
+    fn encode(&self, _s: &mut S) {}
 }
 
-impl<D: serialize::Decoder> serialize::Decodable<D> for PredecessorCache {
+impl<D: Decoder> Decodable<D> for PredecessorCache {
     #[inline]
     fn decode(_: &mut D) -> Self {
         Self::new()
diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs
index 8111409..462c0ad 100644
--- a/compiler/rustc_middle/src/mir/pretty.rs
+++ b/compiler/rustc_middle/src/mir/pretty.rs
@@ -454,8 +454,13 @@
                 ConstValue::ByRef { .. } => format!("ByRef(..)"),
             };
 
+            let fmt_valtree = |valtree: &ty::ValTree<'tcx>| match valtree {
+                ty::ValTree::Leaf(leaf) => format!("ValTree::Leaf({:?})", leaf),
+                ty::ValTree::Branch(_) => format!("ValTree::Branch(..)"),
+            };
+
             let val = match literal {
-                ConstantKind::Ty(ct) => match ct.val() {
+                ConstantKind::Ty(ct) => match ct.kind() {
                     ty::ConstKind::Param(p) => format!("Param({})", p),
                     ty::ConstKind::Unevaluated(uv) => format!(
                         "Unevaluated({}, {:?}, {:?})",
@@ -463,7 +468,7 @@
                         uv.substs,
                         uv.promoted,
                     ),
-                    ty::ConstKind::Value(val) => format!("Value({})", fmt_val(&val)),
+                    ty::ConstKind::Value(val) => format!("Value({})", fmt_valtree(&val)),
                     ty::ConstKind::Error(_) => "Error".to_string(),
                     // These variants shouldn't exist in the MIR.
                     ty::ConstKind::Placeholder(_)
@@ -476,6 +481,9 @@
                 ConstantKind::Val(val, _) => format!("Value({})", fmt_val(&val)),
             };
 
+            // This reflects what `Const` looked liked before `val` was renamed
+            // as `kind`. We print it like this to avoid having to update
+            // expected output in a lot of tests.
             self.push(&format!("+ literal: Const {{ ty: {}, val: {} }}", literal.ty(), val));
         }
     }
@@ -662,7 +670,8 @@
     ) -> impl DoubleEndedIterator<Item = AllocId> + '_ {
         alloc.inner().relocations().values().map(|id| *id)
     }
-    fn alloc_ids_from_const(val: ConstValue<'_>) -> impl Iterator<Item = AllocId> + '_ {
+
+    fn alloc_ids_from_const_val(val: ConstValue<'_>) -> impl Iterator<Item = AllocId> + '_ {
         match val {
             ConstValue::Scalar(interpret::Scalar::Ptr(ptr, _)) => {
                 Either::Left(Either::Left(std::iter::once(ptr.provenance)))
@@ -678,17 +687,11 @@
     struct CollectAllocIds(BTreeSet<AllocId>);
 
     impl<'tcx> Visitor<'tcx> for CollectAllocIds {
-        fn visit_const(&mut self, c: ty::Const<'tcx>, _loc: Location) {
-            if let ty::ConstKind::Value(val) = c.val() {
-                self.0.extend(alloc_ids_from_const(val));
-            }
-        }
-
         fn visit_constant(&mut self, c: &Constant<'tcx>, loc: Location) {
             match c.literal {
                 ConstantKind::Ty(c) => self.visit_const(c, loc),
                 ConstantKind::Val(val, _) => {
-                    self.0.extend(alloc_ids_from_const(val));
+                    self.0.extend(alloc_ids_from_const_val(val));
                 }
             }
         }
@@ -1007,10 +1010,11 @@
     for (index, annotation) in body.user_type_annotations.iter_enumerated() {
         writeln!(
             w,
-            "| {:?}: {:?} at {}",
+            "| {:?}: user_ty: {:?}, span: {}, inferred_ty: {:?}",
             index.index(),
             annotation.user_ty,
-            tcx.sess.source_map().span_to_embeddable_string(annotation.span)
+            tcx.sess.source_map().span_to_embeddable_string(annotation.span),
+            annotation.inferred_ty,
         )?;
     }
     if !body.user_type_annotations.is_empty() {
diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs
index 4d4eed1..da4793f 100644
--- a/compiler/rustc_middle/src/mir/query.rs
+++ b/compiler/rustc_middle/src/mir/query.rs
@@ -1,6 +1,6 @@
 //! Values computed by queries that use MIR.
 
-use crate::mir::{Body, Promoted};
+use crate::mir::{Body, ConstantKind, Promoted};
 use crate::ty::{self, OpaqueHiddenType, Ty, TyCtxt};
 use rustc_data_structures::stable_map::FxHashMap;
 use rustc_data_structures::vec_map::VecMap;
@@ -338,11 +338,12 @@
     pub blame_span: Span,
 
     // ... due to this reason.
-    pub category: ConstraintCategory,
+    pub category: ConstraintCategory<'tcx>,
 }
 
 // Make sure this enum doesn't unintentionally grow
-rustc_data_structures::static_assert_size!(ConstraintCategory, 12);
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+rustc_data_structures::static_assert_size!(ConstraintCategory<'_>, 16);
 
 /// Outlives-constraints can be categorized to determine whether and why they
 /// are interesting (for error reporting). Order of variants indicates sort
@@ -351,7 +352,7 @@
 /// See also `rustc_const_eval::borrow_check::constraints`.
 #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash)]
 #[derive(TyEncodable, TyDecodable, HashStable)]
-pub enum ConstraintCategory {
+pub enum ConstraintCategory<'tcx> {
     Return(ReturnConstraint),
     Yield,
     UseAsConst,
@@ -363,7 +364,9 @@
     ///
     /// We try to get the category that the closure used when reporting this.
     ClosureBounds,
-    CallArgument,
+
+    /// Contains the function type if available.
+    CallArgument(Option<Ty<'tcx>>),
     CopyBound,
     SizedBound,
     Assignment,
@@ -413,13 +416,20 @@
     Region(ty::RegionVid),
 }
 
-/// The constituent parts of an ADT or array.
+/// The constituent parts of a type level constant of kind ADT or array.
 #[derive(Copy, Clone, Debug, HashStable)]
 pub struct DestructuredConst<'tcx> {
     pub variant: Option<VariantIdx>,
     pub fields: &'tcx [ty::Const<'tcx>],
 }
 
+/// The constituent parts of a mir constant of kind ADT or array.
+#[derive(Copy, Clone, Debug, HashStable)]
+pub struct DestructuredMirConstant<'tcx> {
+    pub variant: Option<VariantIdx>,
+    pub fields: &'tcx [ConstantKind<'tcx>],
+}
+
 /// Coverage information summarized from a MIR if instrumented for source code coverage (see
 /// compiler option `-Cinstrument-coverage`). This information is generated by the
 /// `InstrumentCoverage` MIR pass and can be retrieved via the `coverageinfo` query.
diff --git a/compiler/rustc_middle/src/mir/spanview.rs b/compiler/rustc_middle/src/mir/spanview.rs
index afcd5db..4418b84 100644
--- a/compiler/rustc_middle/src/mir/spanview.rs
+++ b/compiler/rustc_middle/src/mir/spanview.rs
@@ -667,7 +667,7 @@
 fn fn_span<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Span {
     let fn_decl_span = tcx.def_span(def_id);
     if let Some(body_span) = hir_body(tcx, def_id).map(|hir_body| hir_body.value.span) {
-        if fn_decl_span.ctxt() == body_span.ctxt() { fn_decl_span.to(body_span) } else { body_span }
+        if fn_decl_span.eq_ctxt(body_span) { fn_decl_span.to(body_span) } else { body_span }
     } else {
         fn_decl_span
     }
diff --git a/compiler/rustc_middle/src/mir/switch_sources.rs b/compiler/rustc_middle/src/mir/switch_sources.rs
index adeeec7..99d13fc 100644
--- a/compiler/rustc_middle/src/mir/switch_sources.rs
+++ b/compiler/rustc_middle/src/mir/switch_sources.rs
@@ -5,7 +5,7 @@
 use rustc_data_structures::stable_map::FxHashMap;
 use rustc_data_structures::sync::OnceCell;
 use rustc_index::vec::IndexVec;
-use rustc_serialize as serialize;
+use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
 use smallvec::SmallVec;
 
 use crate::mir::{BasicBlock, BasicBlockData, Terminator, TerminatorKind};
@@ -54,14 +54,12 @@
     }
 }
 
-impl<S: serialize::Encoder> serialize::Encodable<S> for SwitchSourceCache {
+impl<S: Encoder> Encodable<S> for SwitchSourceCache {
     #[inline]
-    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
-        s.emit_unit()
-    }
+    fn encode(&self, _s: &mut S) {}
 }
 
-impl<D: serialize::Decoder> serialize::Decodable<D> for SwitchSourceCache {
+impl<D: Decoder> Decodable<D> for SwitchSourceCache {
     #[inline]
     fn decode(_: &mut D) -> Self {
         Self::new()
diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs
index e6eb63f..c65e79a 100644
--- a/compiler/rustc_middle/src/mir/terminator.rs
+++ b/compiler/rustc_middle/src/mir/terminator.rs
@@ -1,3 +1,4 @@
+use crate::mir;
 use crate::mir::interpret::Scalar;
 use crate::ty::{self, Ty, TyCtxt};
 use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
@@ -250,8 +251,10 @@
         /// This allows the memory occupied by "by-value" arguments to be
         /// reused across function calls without duplicating the contents.
         args: Vec<Operand<'tcx>>,
-        /// Destination for the return value. If none, the call necessarily diverges.
-        destination: Option<(Place<'tcx>, BasicBlock)>,
+        /// Where the returned value will be written
+        destination: Place<'tcx>,
+        /// Where to go after this call returns. If none, the call necessarily diverges.
+        target: Option<BasicBlock>,
         /// Cleanups to be done if the call unwinds.
         cleanup: Option<BasicBlock>,
         /// `true` if this is from a call in HIR rather than from an overloaded
@@ -415,33 +418,37 @@
             | GeneratorDrop
             | Return
             | Unreachable
-            | Call { destination: None, cleanup: None, .. }
-            | InlineAsm { destination: None, cleanup: None, .. } => None.into_iter().chain(&[]),
-            Goto { target: ref t }
-            | Call { destination: None, cleanup: Some(ref t), .. }
-            | Call { destination: Some((_, ref t)), cleanup: None, .. }
-            | Yield { resume: ref t, drop: None, .. }
-            | DropAndReplace { target: ref t, unwind: None, .. }
-            | Drop { target: ref t, unwind: None, .. }
-            | Assert { target: ref t, cleanup: None, .. }
-            | FalseUnwind { real_target: ref t, unwind: None }
-            | InlineAsm { destination: Some(ref t), cleanup: None, .. }
-            | InlineAsm { destination: None, cleanup: Some(ref t), .. } => {
-                Some(t).into_iter().chain(&[])
+            | Call { target: None, cleanup: None, .. }
+            | InlineAsm { destination: None, cleanup: None, .. } => {
+                None.into_iter().chain((&[]).into_iter().copied())
             }
-            Call { destination: Some((_, ref t)), cleanup: Some(ref u), .. }
-            | Yield { resume: ref t, drop: Some(ref u), .. }
-            | DropAndReplace { target: ref t, unwind: Some(ref u), .. }
-            | Drop { target: ref t, unwind: Some(ref u), .. }
-            | Assert { target: ref t, cleanup: Some(ref u), .. }
-            | FalseUnwind { real_target: ref t, unwind: Some(ref u) }
-            | InlineAsm { destination: Some(ref t), cleanup: Some(ref u), .. } => {
-                Some(t).into_iter().chain(slice::from_ref(u))
+            Goto { target: t }
+            | Call { target: None, cleanup: Some(t), .. }
+            | Call { target: Some(t), cleanup: None, .. }
+            | Yield { resume: t, drop: None, .. }
+            | DropAndReplace { target: t, unwind: None, .. }
+            | Drop { target: t, unwind: None, .. }
+            | Assert { target: t, cleanup: None, .. }
+            | FalseUnwind { real_target: t, unwind: None }
+            | InlineAsm { destination: Some(t), cleanup: None, .. }
+            | InlineAsm { destination: None, cleanup: Some(t), .. } => {
+                Some(t).into_iter().chain((&[]).into_iter().copied())
             }
-            SwitchInt { ref targets, .. } => None.into_iter().chain(&targets.targets),
-            FalseEdge { ref real_target, ref imaginary_target } => {
-                Some(real_target).into_iter().chain(slice::from_ref(imaginary_target))
+            Call { target: Some(t), cleanup: Some(ref u), .. }
+            | Yield { resume: t, drop: Some(ref u), .. }
+            | DropAndReplace { target: t, unwind: Some(ref u), .. }
+            | Drop { target: t, unwind: Some(ref u), .. }
+            | Assert { target: t, cleanup: Some(ref u), .. }
+            | FalseUnwind { real_target: t, unwind: Some(ref u) }
+            | InlineAsm { destination: Some(t), cleanup: Some(ref u), .. } => {
+                Some(t).into_iter().chain(slice::from_ref(u).into_iter().copied())
             }
+            SwitchInt { ref targets, .. } => {
+                None.into_iter().chain(targets.targets.iter().copied())
+            }
+            FalseEdge { real_target, ref imaginary_target } => Some(real_target)
+                .into_iter()
+                .chain(slice::from_ref(imaginary_target).into_iter().copied()),
         }
     }
 
@@ -453,11 +460,11 @@
             | GeneratorDrop
             | Return
             | Unreachable
-            | Call { destination: None, cleanup: None, .. }
+            | Call { target: None, cleanup: None, .. }
             | InlineAsm { destination: None, cleanup: None, .. } => None.into_iter().chain(&mut []),
             Goto { target: ref mut t }
-            | Call { destination: None, cleanup: Some(ref mut t), .. }
-            | Call { destination: Some((_, ref mut t)), cleanup: None, .. }
+            | Call { target: None, cleanup: Some(ref mut t), .. }
+            | Call { target: Some(ref mut t), cleanup: None, .. }
             | Yield { resume: ref mut t, drop: None, .. }
             | DropAndReplace { target: ref mut t, unwind: None, .. }
             | Drop { target: ref mut t, unwind: None, .. }
@@ -467,7 +474,7 @@
             | InlineAsm { destination: None, cleanup: Some(ref mut t), .. } => {
                 Some(t).into_iter().chain(&mut [])
             }
-            Call { destination: Some((_, ref mut t)), cleanup: Some(ref mut u), .. }
+            Call { target: Some(ref mut t), cleanup: Some(ref mut u), .. }
             | Yield { resume: ref mut t, drop: Some(ref mut u), .. }
             | DropAndReplace { target: ref mut t, unwind: Some(ref mut u), .. }
             | Drop { target: ref mut t, unwind: Some(ref mut u), .. }
@@ -586,9 +593,7 @@
                 write!(fmt, "replace({:?} <- {:?})", place, value)
             }
             Call { func, args, destination, .. } => {
-                if let Some((destination, _)) = destination {
-                    write!(fmt, "{:?} = ", destination)?;
-                }
+                write!(fmt, "{:?} = ", destination)?;
                 write!(fmt, "{:?}(", func)?;
                 for (index, arg) in args.iter().enumerate() {
                     if index > 0 {
@@ -672,19 +677,19 @@
                     .values
                     .iter()
                     .map(|&u| {
-                        ty::Const::from_scalar(tcx, Scalar::from_uint(u, size), switch_ty)
+                        mir::ConstantKind::from_scalar(tcx, Scalar::from_uint(u, size), switch_ty)
                             .to_string()
                             .into()
                     })
                     .chain(iter::once("otherwise".into()))
                     .collect()
             }),
-            Call { destination: Some(_), cleanup: Some(_), .. } => {
+            Call { target: Some(_), cleanup: Some(_), .. } => {
                 vec!["return".into(), "unwind".into()]
             }
-            Call { destination: Some(_), cleanup: None, .. } => vec!["return".into()],
-            Call { destination: None, cleanup: Some(_), .. } => vec!["unwind".into()],
-            Call { destination: None, cleanup: None, .. } => vec![],
+            Call { target: Some(_), cleanup: None, .. } => vec!["return".into()],
+            Call { target: None, cleanup: Some(_), .. } => vec!["unwind".into()],
+            Call { target: None, cleanup: None, .. } => vec![],
             Yield { drop: Some(_), .. } => vec!["resume".into(), "drop".into()],
             Yield { drop: None, .. } => vec!["resume".into()],
             DropAndReplace { unwind: None, .. } | Drop { unwind: None, .. } => {
diff --git a/compiler/rustc_middle/src/mir/traversal.rs b/compiler/rustc_middle/src/mir/traversal.rs
index 8d831cc..7228e3f 100644
--- a/compiler/rustc_middle/src/mir/traversal.rs
+++ b/compiler/rustc_middle/src/mir/traversal.rs
@@ -1,7 +1,7 @@
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_data_structures::sync::OnceCell;
 use rustc_index::bit_set::BitSet;
-use rustc_serialize as serialize;
+use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
 
 use super::*;
 
@@ -180,7 +180,7 @@
         // two iterations yield `C` and finally `A` for a final traversal of [E, D, B, C, A]
         loop {
             let bb = if let Some(&mut (_, ref mut iter)) = self.visit_stack.last_mut() {
-                if let Some(&bb) = iter.next() {
+                if let Some(bb) = iter.next() {
                     bb
                 } else {
                     break;
@@ -310,7 +310,7 @@
 #[derive(Clone)]
 pub struct ReversePostorderIter<'a, 'tcx> {
     body: &'a Body<'tcx>,
-    blocks: &'a Vec<BasicBlock>,
+    blocks: &'a [BasicBlock],
     idx: usize,
 }
 
@@ -358,21 +358,19 @@
         self.cache = OnceCell::new();
     }
 
-    /// Returns the &Vec<BasicBlocks> represents the postorder graph for this MIR.
+    /// Returns the `&[BasicBlocks]` represents the postorder graph for this MIR.
     #[inline]
-    pub(super) fn compute(&self, body: &Body<'_>) -> &Vec<BasicBlock> {
+    pub(super) fn compute(&self, body: &Body<'_>) -> &[BasicBlock] {
         self.cache.get_or_init(|| Postorder::new(body, START_BLOCK).map(|(bb, _)| bb).collect())
     }
 }
 
-impl<S: serialize::Encoder> serialize::Encodable<S> for PostorderCache {
+impl<S: Encoder> Encodable<S> for PostorderCache {
     #[inline]
-    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
-        s.emit_unit()
-    }
+    fn encode(&self, _s: &mut S) {}
 }
 
-impl<D: serialize::Decoder> serialize::Decodable<D> for PostorderCache {
+impl<D: Decoder> Decodable<D> for PostorderCache {
     #[inline]
     fn decode(_: &mut D) -> Self {
         Self::new()
diff --git a/compiler/rustc_middle/src/mir/type_foldable.rs b/compiler/rustc_middle/src/mir/type_foldable.rs
index 901f3bf..4201b2d 100644
--- a/compiler/rustc_middle/src/mir/type_foldable.rs
+++ b/compiler/rustc_middle/src/mir/type_foldable.rs
@@ -16,10 +16,7 @@
 }
 
 impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> {
-    fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
-        self,
-        folder: &mut F,
-    ) -> Result<Self, F::Error> {
+    fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
         use crate::mir::TerminatorKind::*;
 
         let kind = match self.kind {
@@ -44,20 +41,15 @@
                 resume_arg: resume_arg.try_fold_with(folder)?,
                 drop,
             },
-            Call { func, args, destination, cleanup, from_hir_call, fn_span } => {
-                let dest = destination
-                    .map(|(loc, dest)| (loc.try_fold_with(folder).map(|loc| (loc, dest))))
-                    .transpose()?;
-
-                Call {
-                    func: func.try_fold_with(folder)?,
-                    args: args.try_fold_with(folder)?,
-                    destination: dest,
-                    cleanup,
-                    from_hir_call,
-                    fn_span,
-                }
-            }
+            Call { func, args, destination, target, cleanup, from_hir_call, fn_span } => Call {
+                func: func.try_fold_with(folder)?,
+                args: args.try_fold_with(folder)?,
+                destination: destination.try_fold_with(folder)?,
+                target,
+                cleanup,
+                from_hir_call,
+                fn_span,
+            },
             Assert { cond, expected, msg, target, cleanup } => {
                 use AssertKind::*;
                 let msg = match msg {
@@ -98,7 +90,7 @@
         Ok(Terminator { source_info: self.source_info, kind })
     }
 
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         use crate::mir::TerminatorKind::*;
 
         match self.kind {
@@ -113,9 +105,7 @@
             }
             Yield { ref value, .. } => value.visit_with(visitor),
             Call { ref func, ref args, ref destination, .. } => {
-                if let Some((ref loc, _)) = *destination {
-                    loc.visit_with(visitor)?;
-                };
+                destination.visit_with(visitor)?;
                 func.visit_with(visitor)?;
                 args.visit_with(visitor)
             }
@@ -151,50 +141,41 @@
 }
 
 impl<'tcx> TypeFoldable<'tcx> for GeneratorKind {
-    fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(self, _: &mut F) -> Result<Self, F::Error> {
+    fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, _: &mut F) -> Result<Self, F::Error> {
         Ok(self)
     }
 
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<V::BreakTy> {
+    fn visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<V::BreakTy> {
         ControlFlow::CONTINUE
     }
 }
 
 impl<'tcx> TypeFoldable<'tcx> for Place<'tcx> {
-    fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
-        self,
-        folder: &mut F,
-    ) -> Result<Self, F::Error> {
+    fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
         Ok(Place {
             local: self.local.try_fold_with(folder)?,
             projection: self.projection.try_fold_with(folder)?,
         })
     }
 
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         self.local.visit_with(visitor)?;
         self.projection.visit_with(visitor)
     }
 }
 
 impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<PlaceElem<'tcx>> {
-    fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
-        self,
-        folder: &mut F,
-    ) -> Result<Self, F::Error> {
+    fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
         ty::util::fold_list(self, folder, |tcx, v| tcx.intern_place_elems(v))
     }
 
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         self.iter().try_for_each(|t| t.visit_with(visitor))
     }
 }
 
 impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> {
-    fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
-        self,
-        folder: &mut F,
-    ) -> Result<Self, F::Error> {
+    fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
         use crate::mir::Rvalue::*;
         Ok(match self {
             Use(op) => Use(op.try_fold_with(folder)?),
@@ -244,7 +225,7 @@
         })
     }
 
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         use crate::mir::Rvalue::*;
         match *self {
             Use(ref op) => op.visit_with(visitor),
@@ -295,10 +276,7 @@
 }
 
 impl<'tcx> TypeFoldable<'tcx> for Operand<'tcx> {
-    fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
-        self,
-        folder: &mut F,
-    ) -> Result<Self, F::Error> {
+    fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
         Ok(match self {
             Operand::Copy(place) => Operand::Copy(place.try_fold_with(folder)?),
             Operand::Move(place) => Operand::Move(place.try_fold_with(folder)?),
@@ -306,7 +284,7 @@
         })
     }
 
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         match *self {
             Operand::Copy(ref place) | Operand::Move(ref place) => place.visit_with(visitor),
             Operand::Constant(ref c) => c.visit_with(visitor),
@@ -315,10 +293,7 @@
 }
 
 impl<'tcx> TypeFoldable<'tcx> for PlaceElem<'tcx> {
-    fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
-        self,
-        folder: &mut F,
-    ) -> Result<Self, F::Error> {
+    fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
         use crate::mir::ProjectionElem::*;
 
         Ok(match self {
@@ -333,10 +308,7 @@
         })
     }
 
-    fn super_visit_with<Vs: TypeVisitor<'tcx>>(
-        &self,
-        visitor: &mut Vs,
-    ) -> ControlFlow<Vs::BreakTy> {
+    fn visit_with<Vs: TypeVisitor<'tcx>>(&self, visitor: &mut Vs) -> ControlFlow<Vs::BreakTy> {
         use crate::mir::ProjectionElem::*;
 
         match self {
@@ -348,44 +320,41 @@
 }
 
 impl<'tcx> TypeFoldable<'tcx> for Field {
-    fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(self, _: &mut F) -> Result<Self, F::Error> {
+    fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, _: &mut F) -> Result<Self, F::Error> {
         Ok(self)
     }
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<V::BreakTy> {
+    fn visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<V::BreakTy> {
         ControlFlow::CONTINUE
     }
 }
 
 impl<'tcx> TypeFoldable<'tcx> for GeneratorSavedLocal {
-    fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(self, _: &mut F) -> Result<Self, F::Error> {
+    fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, _: &mut F) -> Result<Self, F::Error> {
         Ok(self)
     }
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<V::BreakTy> {
+    fn visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<V::BreakTy> {
         ControlFlow::CONTINUE
     }
 }
 
 impl<'tcx, R: Idx, C: Idx> TypeFoldable<'tcx> for BitMatrix<R, C> {
-    fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(self, _: &mut F) -> Result<Self, F::Error> {
+    fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, _: &mut F) -> Result<Self, F::Error> {
         Ok(self)
     }
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<V::BreakTy> {
+    fn visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<V::BreakTy> {
         ControlFlow::CONTINUE
     }
 }
 
 impl<'tcx> TypeFoldable<'tcx> for Constant<'tcx> {
-    fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
-        self,
-        folder: &mut F,
-    ) -> Result<Self, F::Error> {
+    fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
         Ok(Constant {
             span: self.span,
             user_ty: self.user_ty.try_fold_with(folder)?,
             literal: self.literal.try_fold_with(folder)?,
         })
     }
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         self.literal.visit_with(visitor)?;
         self.user_ty.visit_with(visitor)
     }
@@ -397,6 +366,12 @@
         folder.try_fold_mir_const(self)
     }
 
+    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+        visitor.visit_mir_const(*self)
+    }
+}
+
+impl<'tcx> TypeSuperFoldable<'tcx> for ConstantKind<'tcx> {
     fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
         self,
         folder: &mut F,
diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs
index ef4f1f5..5ce92d1 100644
--- a/compiler/rustc_middle/src/mir/visit.rs
+++ b/compiler/rustc_middle/src/mir/visit.rs
@@ -258,7 +258,7 @@
                 // for best performance, we want to use an iterator rather
                 // than a for-loop, to avoid calling `body::Body::invalidate` for
                 // each basic block.
-                #[cfg_attr(not(bootstrap), allow(unused_macro_rules))]
+                #[allow(unused_macro_rules)]
                 macro_rules! basic_blocks {
                     (mut) => (body.basic_blocks_mut().iter_enumerated_mut());
                     () => (body.basic_blocks().iter_enumerated());
@@ -280,7 +280,7 @@
                     self.visit_local_decl(local, & $($mutability)? body.local_decls[local]);
                 }
 
-                #[cfg_attr(not(bootstrap), allow(unused_macro_rules))]
+                #[allow(unused_macro_rules)]
                 macro_rules! type_annotations {
                     (mut) => (body.user_type_annotations.iter_enumerated_mut());
                     () => (body.user_type_annotations.iter_enumerated());
@@ -534,6 +534,7 @@
                         func,
                         args,
                         destination,
+                        target: _,
                         cleanup: _,
                         from_hir_call: _,
                         fn_span: _
@@ -542,13 +543,11 @@
                         for arg in args {
                             self.visit_operand(arg, location);
                         }
-                        if let Some((destination, _)) = destination {
-                            self.visit_place(
-                                destination,
-                                PlaceContext::MutatingUse(MutatingUseContext::Call),
-                                location
-                            );
-                        }
+                        self.visit_place(
+                            destination,
+                            PlaceContext::MutatingUse(MutatingUseContext::Call),
+                            location
+                        );
                     }
 
                     TerminatorKind::Assert {
@@ -934,7 +933,7 @@
                 body: &$($mutability)? Body<'tcx>,
                 location: Location
             ) {
-                #[cfg_attr(not(bootstrap), allow(unused_macro_rules))]
+                #[allow(unused_macro_rules)]
                 macro_rules! basic_blocks {
                     (mut) => (body.basic_blocks_mut());
                     () => (body.basic_blocks());
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 6d7ec24..29a691f 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -59,6 +59,7 @@
     query hir_module_items(key: LocalDefId) -> rustc_middle::hir::ModuleItems {
         storage(ArenaCacheSelector<'tcx>)
         desc { |tcx| "HIR module items in `{}`", tcx.def_path_str(key.to_def_id()) }
+        cache_on_disk_if { true }
     }
 
     /// Gives access to the HIR node for the HIR owner `key`.
@@ -128,6 +129,7 @@
     /// parameter. e.g. `fn example<const N: usize=3>` called on `N` would return `3`.
     query const_param_default(param: DefId) -> ty::Const<'tcx> {
         desc { |tcx| "compute const default for a given parameter `{}`", tcx.def_path_str(param)  }
+        cache_on_disk_if { param.is_local() }
         separate_provide_extern
     }
 
@@ -223,6 +225,7 @@
     /// Bounds from the parent (e.g. with nested impl trait) are not included.
     query explicit_item_bounds(key: DefId) -> &'tcx [(ty::Predicate<'tcx>, Span)] {
         desc { |tcx| "finding item bounds for `{}`", tcx.def_path_str(key) }
+        cache_on_disk_if { key.is_local() }
         separate_provide_extern
     }
 
@@ -268,8 +271,6 @@
     }
 
     query expn_that_defined(key: DefId) -> rustc_span::ExpnId {
-        // This query reads from untracked data in definitions.
-        eval_always
         desc { |tcx| "expansion that defined `{}`", tcx.def_path_str(key) }
         separate_provide_extern
     }
@@ -508,6 +509,7 @@
     /// Returns the predicates written explicitly by the user.
     query explicit_predicates_of(key: DefId) -> ty::GenericPredicates<'tcx> {
         desc { |tcx| "computing explicit predicates of `{}`", tcx.def_path_str(key) }
+        cache_on_disk_if { key.is_local() }
         separate_provide_extern
     }
 
@@ -515,6 +517,7 @@
     /// Foo<'a, T> { x: &'a T }`, this would return `T: 'a`).
     query inferred_outlives_of(key: DefId) -> &'tcx [(ty::Predicate<'tcx>, Span)] {
         desc { |tcx| "computing inferred outlives predicates of `{}`", tcx.def_path_str(key) }
+        cache_on_disk_if { key.is_local() }
         separate_provide_extern
     }
 
@@ -526,6 +529,7 @@
     /// additional acyclicity requirements).
     query super_predicates_of(key: DefId) -> ty::GenericPredicates<'tcx> {
         desc { |tcx| "computing the super predicates of `{}`", tcx.def_path_str(key) }
+        cache_on_disk_if { key.is_local() }
         separate_provide_extern
     }
 
@@ -549,6 +553,7 @@
     query trait_def(key: DefId) -> ty::TraitDef {
         desc { |tcx| "computing trait definition for `{}`", tcx.def_path_str(key) }
         storage(ArenaCacheSelector<'tcx>)
+        cache_on_disk_if { key.is_local() }
         separate_provide_extern
     }
     query adt_def(key: DefId) -> ty::AdtDef<'tcx> {
@@ -558,6 +563,7 @@
     }
     query adt_destructor(key: DefId) -> Option<ty::Destructor> {
         desc { |tcx| "computing `Drop` impl for `{}`", tcx.def_path_str(key) }
+        cache_on_disk_if { key.is_local() }
         separate_provide_extern
     }
 
@@ -584,14 +590,16 @@
     /// not have the feature gate active).
     ///
     /// **Do not call this function manually.** It is only meant to cache the base data for the
-    /// `is_const_fn` function.
-    query impl_constness(key: DefId) -> hir::Constness {
-        desc { |tcx| "checking if item is const fn: `{}`", tcx.def_path_str(key) }
+    /// `is_const_fn` function. Consider using `is_const_fn` or `is_const_fn_raw` instead.
+    query constness(key: DefId) -> hir::Constness {
+        desc { |tcx| "checking if item is const: `{}`", tcx.def_path_str(key) }
+        cache_on_disk_if { key.is_local() }
         separate_provide_extern
     }
 
     query asyncness(key: DefId) -> hir::IsAsync {
         desc { |tcx| "checking if the function is async: `{}`", tcx.def_path_str(key) }
+        cache_on_disk_if { key.is_local() }
         separate_provide_extern
     }
 
@@ -609,12 +617,14 @@
     /// Returns `true` if this is a foreign item (i.e., linked via `extern { ... }`).
     query is_foreign_item(key: DefId) -> bool {
         desc { |tcx| "checking if `{}` is a foreign item", tcx.def_path_str(key) }
+        cache_on_disk_if { key.is_local() }
         separate_provide_extern
     }
 
     /// Returns `Some(generator_kind)` if the node pointed to by `def_id` is a generator.
     query generator_kind(def_id: DefId) -> Option<hir::GeneratorKind> {
         desc { |tcx| "looking up generator kind of `{}`", tcx.def_path_str(def_id) }
+        cache_on_disk_if { def_id.is_local() }
         separate_provide_extern
     }
 
@@ -627,6 +637,7 @@
     /// Maps from the `DefId` of a type or region parameter to its (inferred) variance.
     query variances_of(def_id: DefId) -> &'tcx [ty::Variance] {
         desc { |tcx| "computing the variances of `{}`", tcx.def_path_str(def_id) }
+        cache_on_disk_if { def_id.is_local() }
         separate_provide_extern
     }
 
@@ -639,6 +650,7 @@
     /// Maps from an impl/trait `DefId` to a list of the `DefId`s of its items.
     query associated_item_def_ids(key: DefId) -> &'tcx [DefId] {
         desc { |tcx| "collecting associated items of `{}`", tcx.def_path_str(key) }
+        cache_on_disk_if { key.is_local() }
         separate_provide_extern
     }
 
@@ -646,6 +658,7 @@
     query associated_item(key: DefId) -> ty::AssocItem {
         desc { |tcx| "computing associated item data for `{}`", tcx.def_path_str(key) }
         storage(ArenaCacheSelector<'tcx>)
+        cache_on_disk_if { key.is_local() }
         separate_provide_extern
     }
 
@@ -685,10 +698,12 @@
     /// Return `None` if this is an inherent impl.
     query impl_trait_ref(impl_id: DefId) -> Option<ty::TraitRef<'tcx>> {
         desc { |tcx| "computing trait implemented by `{}`", tcx.def_path_str(impl_id) }
+        cache_on_disk_if { impl_id.is_local() }
         separate_provide_extern
     }
     query impl_polarity(impl_id: DefId) -> ty::ImplPolarity {
         desc { |tcx| "computing implementation polarity of `{}`", tcx.def_path_str(impl_id) }
+        cache_on_disk_if { impl_id.is_local() }
         separate_provide_extern
     }
 
@@ -701,6 +716,7 @@
     /// Methods in these implementations don't need to be exported.
     query inherent_impls(key: DefId) -> &'tcx [DefId] {
         desc { |tcx| "collecting inherent impls for `{}`", tcx.def_path_str(key) }
+        cache_on_disk_if { key.is_local() }
         separate_provide_extern
     }
 
@@ -745,6 +761,7 @@
     /// Computes the signature of the function.
     query fn_sig(key: DefId) -> ty::PolyFnSig<'tcx> {
         desc { |tcx| "computing function signature of `{}`", tcx.def_path_str(key) }
+        cache_on_disk_if { key.is_local() }
         separate_provide_extern
     }
 
@@ -785,10 +802,6 @@
         desc { |tcx| "checking privacy in {}", describe_as_module(key, tcx) }
     }
 
-    query check_mod_intrinsics(key: LocalDefId) -> () {
-        desc { |tcx| "checking intrinsics in {}", describe_as_module(key, tcx) }
-    }
-
     query check_mod_liveness(key: LocalDefId) -> () {
         desc { |tcx| "checking liveness of variables in {}", describe_as_module(key, tcx) }
     }
@@ -820,6 +833,7 @@
     /// Caches `CoerceUnsized` kinds for impls on custom types.
     query coerce_unsized_info(key: DefId) -> ty::adjustment::CoerceUnsizedInfo {
         desc { |tcx| "computing CoerceUnsized info for `{}`", tcx.def_path_str(key) }
+        cache_on_disk_if { key.is_local() }
         separate_provide_extern
     }
 
@@ -946,37 +960,40 @@
         cache_on_disk_if { true }
     }
 
-    /// Convert an evaluated constant to a type level constant or
+    /// Evaluate a constant and convert it to a type level constant or
     /// return `None` if that is not possible.
-    query const_to_valtree(
-        key: ty::ParamEnvAnd<'tcx, ConstAlloc<'tcx>>
-    ) -> Option<ty::ValTree<'tcx>> {
-        desc { "destructure constant" }
-        remap_env_constness
+    query eval_to_valtree(
+        key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>
+    ) -> EvalToValTreeResult<'tcx> {
+        desc { "evaluating type-level constant" }
     }
 
     /// Converts a type level constant value into `ConstValue`
     query valtree_to_const_val(key: (Ty<'tcx>, ty::ValTree<'tcx>)) -> ConstValue<'tcx> {
-        desc { "convert type-level constant value to mir constant value"}
+        desc { "converting type-level constant value to mir constant value"}
     }
 
     /// Destructure a constant ADT or array into its variant index and its
     /// field values or return `None` if constant is invalid.
     ///
     /// Use infallible `TyCtxt::destructure_const` when you know that constant is valid.
-    query try_destructure_const(
-        key: ty::ParamEnvAnd<'tcx, ty::Const<'tcx>>
-    ) -> Option<mir::DestructuredConst<'tcx>> {
-        desc { "destructure constant" }
+    query try_destructure_const(key: ty::Const<'tcx>) -> Option<ty::DestructuredConst<'tcx>> {
+        desc { "destructuring type level constant"}
+    }
+
+    /// Tries to destructure an `mir::ConstantKind` ADT or array into its variant index
+    /// and its field values.
+    query try_destructure_mir_constant(key: ty::ParamEnvAnd<'tcx, mir::ConstantKind<'tcx>>) -> Option<mir::DestructuredMirConstant<'tcx>> {
+        desc { "destructuring mir constant"}
         remap_env_constness
     }
 
     /// Dereference a constant reference or raw pointer and turn the result into a constant
     /// again.
-    query deref_const(
-        key: ty::ParamEnvAnd<'tcx, ty::Const<'tcx>>
-    ) -> ty::Const<'tcx> {
-        desc { "deref constant" }
+    query deref_mir_constant(
+        key: ty::ParamEnvAnd<'tcx, mir::ConstantKind<'tcx>>
+    ) -> mir::ConstantKind<'tcx> {
+        desc { "dereferencing mir constant" }
         remap_env_constness
     }
 
@@ -991,6 +1008,10 @@
         desc { "converting literal to const" }
     }
 
+    query lit_to_mir_constant(key: LitToConstInput<'tcx>) -> Result<mir::ConstantKind<'tcx>, LitToConstError> {
+        desc { "converting literal to mir constant" }
+    }
+
     query check_match(key: DefId) {
         desc { |tcx| "match-checking `{}`", tcx.def_path_str(key) }
         cache_on_disk_if { key.is_local() }
@@ -1013,7 +1034,7 @@
 
     /// Per-body `region::ScopeTree`. The `DefId` should be the owner `DefId` for the body;
     /// in the case of closures, this will be redirected to the enclosing function.
-    query region_scope_tree(def_id: DefId) -> &'tcx region::ScopeTree {
+    query region_scope_tree(def_id: DefId) -> &'tcx crate::middle::region::ScopeTree {
         desc { |tcx| "computing drop scopes for `{}`", tcx.def_path_str(def_id) }
     }
 
@@ -1033,28 +1054,33 @@
 
     query opt_def_kind(def_id: DefId) -> Option<DefKind> {
         desc { |tcx| "looking up definition kind of `{}`", tcx.def_path_str(def_id) }
+        cache_on_disk_if { def_id.is_local() }
         separate_provide_extern
     }
 
     /// Gets the span for the definition.
     query def_span(def_id: DefId) -> Span {
         desc { |tcx| "looking up span for `{}`", tcx.def_path_str(def_id) }
+        cache_on_disk_if { def_id.is_local() }
         separate_provide_extern
     }
 
     /// Gets the span for the identifier of the definition.
     query def_ident_span(def_id: DefId) -> Option<Span> {
         desc { |tcx| "looking up span for `{}`'s identifier", tcx.def_path_str(def_id) }
+        cache_on_disk_if { def_id.is_local() }
         separate_provide_extern
     }
 
     query lookup_stability(def_id: DefId) -> Option<attr::Stability> {
         desc { |tcx| "looking up stability of `{}`", tcx.def_path_str(def_id) }
+        cache_on_disk_if { def_id.is_local() }
         separate_provide_extern
     }
 
     query lookup_const_stability(def_id: DefId) -> Option<attr::ConstStability> {
         desc { |tcx| "looking up const stability of `{}`", tcx.def_path_str(def_id) }
+        cache_on_disk_if { def_id.is_local() }
         separate_provide_extern
     }
 
@@ -1064,6 +1090,7 @@
 
     query lookup_deprecation_entry(def_id: DefId) -> Option<DeprecationEntry> {
         desc { |tcx| "checking whether `{}` is deprecated", tcx.def_path_str(def_id) }
+        cache_on_disk_if { def_id.is_local() }
         separate_provide_extern
     }
 
@@ -1093,6 +1120,7 @@
 
     query fn_arg_names(def_id: DefId) -> &'tcx [rustc_span::symbol::Ident] {
         desc { |tcx| "looking up function parameter names for `{}`", tcx.def_path_str(def_id) }
+        cache_on_disk_if { def_id.is_local() }
         separate_provide_extern
     }
     /// Gets the rendered value of the specified constant or associated constant.
@@ -1100,10 +1128,12 @@
     query rendered_const(def_id: DefId) -> String {
         storage(ArenaCacheSelector<'tcx>)
         desc { |tcx| "rendering constant intializer of `{}`", tcx.def_path_str(def_id) }
+        cache_on_disk_if { def_id.is_local() }
         separate_provide_extern
     }
     query impl_parent(def_id: DefId) -> Option<DefId> {
         desc { |tcx| "computing specialization parent impl of `{}`", tcx.def_path_str(def_id) }
+        cache_on_disk_if { def_id.is_local() }
         separate_provide_extern
     }
 
@@ -1111,15 +1141,18 @@
     /// Return `None` if the `DefId` is not an associated item.
     query trait_of_item(associated_item: DefId) -> Option<DefId> {
         desc { |tcx| "finding trait defining `{}`", tcx.def_path_str(associated_item) }
+        cache_on_disk_if { associated_item.is_local() }
         separate_provide_extern
     }
 
     query is_ctfe_mir_available(key: DefId) -> bool {
         desc { |tcx| "checking if item has ctfe mir available: `{}`", tcx.def_path_str(key) }
+        cache_on_disk_if { key.is_local() }
         separate_provide_extern
     }
     query is_mir_available(key: DefId) -> bool {
         desc { |tcx| "checking if item has mir available: `{}`", tcx.def_path_str(key) }
+        cache_on_disk_if { key.is_local() }
         separate_provide_extern
     }
 
@@ -1361,6 +1394,7 @@
 
     query impl_defaultness(def_id: DefId) -> hir::Defaultness {
         desc { |tcx| "looking up whether `{}` is a default impl", tcx.def_path_str(def_id) }
+        cache_on_disk_if { def_id.is_local() }
         separate_provide_extern
     }
 
@@ -1394,6 +1428,7 @@
     }
     query is_reachable_non_generic(def_id: DefId) -> bool {
         desc { |tcx| "checking whether `{}` is an exported symbol", tcx.def_path_str(def_id) }
+        cache_on_disk_if { def_id.is_local() }
         separate_provide_extern
     }
     query is_unreachable_local_definition(def_id: LocalDefId) -> bool {
@@ -1537,7 +1572,7 @@
         Option<&'tcx FxHashMap<ItemLocalId, Region>> {
         desc { "looking up a named region" }
     }
-    query is_late_bound_map(_: LocalDefId) -> Option<(LocalDefId, &'tcx FxHashSet<LocalDefId>)> {
+    query is_late_bound_map(_: LocalDefId) -> Option<&'tcx FxIndexSet<LocalDefId>> {
         desc { "testing if a region is late bound" }
     }
     /// For a given item (like a struct), gets the default lifetimes to be used
@@ -1552,11 +1587,6 @@
         desc { "looking up late bound vars" }
     }
 
-    query lifetime_scope_map(_: LocalDefId) -> Option<FxHashMap<ItemLocalId, LifetimeScopeForPath>> {
-        storage(ArenaCacheSelector<'tcx>)
-        desc { "finds the lifetime scope for an HirId of a PathSegment" }
-    }
-
     query visibility(def_id: DefId) -> ty::Visibility {
         desc { |tcx| "computing visibility of `{}`", tcx.def_path_str(def_id) }
         separate_provide_extern
@@ -1601,6 +1631,11 @@
         desc { "calculating the lib features defined in a crate" }
         separate_provide_extern
     }
+    /// Whether the function is an intrinsic
+    query is_intrinsic(def_id: DefId) -> bool {
+        desc { |tcx| "is_intrinsic({})", tcx.def_path_str(def_id) }
+        separate_provide_extern
+    }
     /// Returns the lang items defined in another crate by loading it from metadata.
     query get_lang_items(_: ()) -> LanguageItems {
         storage(ArenaCacheSelector<'tcx>)
@@ -1676,8 +1711,8 @@
     query upvars_mentioned(def_id: DefId) -> Option<&'tcx FxIndexMap<hir::HirId, hir::Upvar>> {
         desc { |tcx| "collecting upvars mentioned in `{}`", tcx.def_path_str(def_id) }
     }
-    query maybe_unused_trait_import(def_id: LocalDefId) -> bool {
-        desc { |tcx| "maybe_unused_trait_import for `{}`", tcx.def_path_str(def_id.to_def_id()) }
+    query maybe_unused_trait_imports(_: ()) -> &'tcx FxIndexSet<LocalDefId> {
+        desc { "fetching potentially unused trait imports" }
     }
     query maybe_unused_extern_crates(_: ()) -> &'tcx [(LocalDefId, Span)] {
         desc { "looking up all possibly unused extern crates" }
@@ -1708,9 +1743,9 @@
     /// - All names contained in `exported_symbols(cnum)` are guaranteed to
     ///   correspond to a publicly visible symbol in `cnum` machine code.
     /// - The `exported_symbols` sets of different crates do not intersect.
-    query exported_symbols(_: CrateNum)
-        -> &'tcx [(ExportedSymbol<'tcx>, SymbolExportInfo)] {
+    query exported_symbols(cnum: CrateNum) -> &'tcx [(ExportedSymbol<'tcx>, SymbolExportInfo)] {
         desc { "exported_symbols" }
+        cache_on_disk_if { *cnum == LOCAL_CRATE }
         separate_provide_extern
     }
 
diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs
index fdf5ecf..120d09e 100644
--- a/compiler/rustc_middle/src/thir.rs
+++ b/compiler/rustc_middle/src/thir.rs
@@ -18,15 +18,11 @@
 use rustc_middle::infer::canonical::Canonical;
 use rustc_middle::middle::region;
 use rustc_middle::mir::interpret::AllocId;
-use rustc_middle::mir::{
-    self, BinOp, BorrowKind, FakeReadCause, Field, Mutability, UnOp, UserTypeProjection,
-};
+use rustc_middle::mir::{self, BinOp, BorrowKind, FakeReadCause, Field, Mutability, UnOp};
 use rustc_middle::ty::adjustment::PointerCast;
 use rustc_middle::ty::subst::SubstsRef;
+use rustc_middle::ty::CanonicalUserTypeAnnotation;
 use rustc_middle::ty::{self, AdtDef, Ty, UpvarSubsts, UserType};
-use rustc_middle::ty::{
-    CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations,
-};
 use rustc_span::{Span, Symbol, DUMMY_SP};
 use rustc_target::abi::VariantIdx;
 use rustc_target::asm::InlineAsmRegOrRegClass;
@@ -195,6 +191,20 @@
 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
 rustc_data_structures::static_assert_size!(Expr<'_>, 104);
 
+#[derive(
+    Clone,
+    Debug,
+    Copy,
+    PartialEq,
+    Eq,
+    Hash,
+    HashStable,
+    TyEncodable,
+    TyDecodable,
+    TypeFoldable
+)]
+pub struct LocalVarId(pub hir::HirId);
+
 /// A THIR expression.
 #[derive(Clone, Debug, HashStable)]
 pub struct Expr<'tcx> {
@@ -321,9 +331,11 @@
         lhs: ExprId,
         rhs: ExprId,
     },
-    /// Access to a struct or tuple field.
+    /// Access to a field of a struct, a tuple, an union, or an enum.
     Field {
         lhs: ExprId,
+        /// Variant containing the field.
+        variant_index: VariantIdx,
         /// This can be a named (`.foo`) or unnamed (`.0`) field.
         name: Field,
     },
@@ -334,7 +346,7 @@
     },
     /// A local variable.
     VarRef {
-        id: hir::HirId,
+        id: LocalVarId,
     },
     /// Used to represent upvars mentioned in a closure/generator
     UpvarRef {
@@ -342,7 +354,7 @@
         closure_def_id: DefId,
 
         /// HirId of the root variable
-        var_hir_id: hir::HirId,
+        var_hir_id: LocalVarId,
     },
     /// A borrow, e.g. `&arg`.
     Borrow {
@@ -540,13 +552,13 @@
     ByRef(BorrowKind),
 }
 
-#[derive(Clone, Debug, PartialEq, HashStable)]
+#[derive(Clone, Debug, HashStable)]
 pub struct FieldPat<'tcx> {
     pub field: Field,
     pub pattern: Pat<'tcx>,
 }
 
-#[derive(Clone, Debug, PartialEq, HashStable)]
+#[derive(Clone, Debug, HashStable)]
 pub struct Pat<'tcx> {
     pub ty: Ty<'tcx>,
     pub span: Span,
@@ -559,37 +571,10 @@
     }
 }
 
-#[derive(Copy, Clone, Debug, PartialEq, HashStable)]
-pub struct PatTyProj<'tcx> {
-    pub user_ty: CanonicalUserType<'tcx>,
-}
-
-impl<'tcx> PatTyProj<'tcx> {
-    pub fn from_user_type(user_annotation: CanonicalUserType<'tcx>) -> Self {
-        Self { user_ty: user_annotation }
-    }
-
-    pub fn user_ty(
-        self,
-        annotations: &mut CanonicalUserTypeAnnotations<'tcx>,
-        inferred_ty: Ty<'tcx>,
-        span: Span,
-    ) -> UserTypeProjection {
-        UserTypeProjection {
-            base: annotations.push(CanonicalUserTypeAnnotation {
-                span,
-                user_ty: self.user_ty,
-                inferred_ty,
-            }),
-            projs: Vec::new(),
-        }
-    }
-}
-
-#[derive(Copy, Clone, Debug, PartialEq, HashStable)]
+#[derive(Clone, Debug, HashStable)]
 pub struct Ascription<'tcx> {
-    pub user_ty: PatTyProj<'tcx>,
-    /// Variance to use when relating the type `user_ty` to the **type of the value being
+    pub annotation: CanonicalUserTypeAnnotation<'tcx>,
+    /// Variance to use when relating the `user_ty` to the **type of the value being
     /// matched**. Typically, this is `Variance::Covariant`, since the value being matched must
     /// have a type that is some subtype of the ascribed type.
     ///
@@ -608,12 +593,11 @@
     /// probably be checking for a `PartialEq` impl instead, but this preserves the behavior
     /// of the old type-check for now. See #57280 for details.
     pub variance: ty::Variance,
-    pub user_ty_span: Span,
 }
 
-#[derive(Clone, Debug, PartialEq, HashStable)]
+#[derive(Clone, Debug, HashStable)]
 pub enum PatKind<'tcx> {
-    /// A wildward pattern: `_`.
+    /// A wildcard pattern: `_`.
     Wild,
 
     AscribeUserType {
@@ -626,7 +610,7 @@
         mutability: Mutability,
         name: Symbol,
         mode: BindingMode,
-        var: hir::HirId,
+        var: LocalVarId,
         ty: Ty<'tcx>,
         subpattern: Option<Pat<'tcx>>,
         /// Is this the leftmost occurrence of the binding, i.e., is `var` the
@@ -662,7 +646,7 @@
     /// * Opaque constants, that must not be matched structurally. So anything that does not derive
     ///   `PartialEq` and `Eq`.
     Constant {
-        value: ty::Const<'tcx>,
+        value: mir::ConstantKind<'tcx>,
     },
 
     Range(PatRange<'tcx>),
@@ -692,8 +676,8 @@
 
 #[derive(Copy, Clone, Debug, PartialEq, HashStable)]
 pub struct PatRange<'tcx> {
-    pub lo: ty::Const<'tcx>,
-    pub hi: ty::Const<'tcx>,
+    pub lo: mir::ConstantKind<'tcx>,
+    pub hi: mir::ConstantKind<'tcx>,
     pub end: RangeEnd,
 }
 
diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs
index f575695..8c8ebb0 100644
--- a/compiler/rustc_middle/src/thir/visit.rs
+++ b/compiler/rustc_middle/src/thir/visit.rs
@@ -80,7 +80,7 @@
             visitor.visit_expr(&visitor.thir()[lhs]);
             visitor.visit_expr(&visitor.thir()[rhs]);
         }
-        Field { lhs, name: _ } => visitor.visit_expr(&visitor.thir()[lhs]),
+        Field { lhs, variant_index: _, name: _ } => visitor.visit_expr(&visitor.thir()[lhs]),
         Index { lhs, index } => {
             visitor.visit_expr(&visitor.thir()[lhs]);
             visitor.visit_expr(&visitor.thir()[index]);
diff --git a/compiler/rustc_middle/src/traits/chalk.rs b/compiler/rustc_middle/src/traits/chalk.rs
index 015bdb5..70abdb9 100644
--- a/compiler/rustc_middle/src/traits/chalk.rs
+++ b/compiler/rustc_middle/src/traits/chalk.rs
@@ -5,7 +5,6 @@
 //! its name suggest, is to provide an abstraction boundary for creating
 //! interned Chalk types.
 
-use rustc_middle::mir::interpret::ConstValue;
 use rustc_middle::ty::{self, AdtDef, TyCtxt};
 
 use rustc_hir::def_id::DefId;
@@ -62,7 +61,7 @@
     type InternedType = Box<chalk_ir::TyData<Self>>;
     type InternedLifetime = Box<chalk_ir::LifetimeData<Self>>;
     type InternedConst = Box<chalk_ir::ConstData<Self>>;
-    type InternedConcreteConst = ConstValue<'tcx>;
+    type InternedConcreteConst = ty::ValTree<'tcx>;
     type InternedGenericArg = Box<chalk_ir::GenericArgData<Self>>;
     type InternedGoal = Box<chalk_ir::GoalData<Self>>;
     type InternedGoals = Vec<chalk_ir::Goal<Self>>;
diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs
index 8c660e3..5258d37 100644
--- a/compiler/rustc_middle/src/traits/mod.rs
+++ b/compiler/rustc_middle/src/traits/mod.rs
@@ -61,6 +61,9 @@
     ///     let x: <() as Assoc>::Output = true;
     /// }
     /// ```
+    ///
+    /// We also do not reveal the hidden type of opaque types during
+    /// type-checking.
     UserFacing,
 
     /// At codegen time, all monomorphic projections will succeed.
@@ -97,9 +100,7 @@
     /// information.
     pub body_id: hir::HirId,
 
-    /// `None` for `MISC_OBLIGATION_CAUSE_CODE` (a common case, occurs ~60% of
-    /// the time). `Some` otherwise.
-    code: Option<Lrc<ObligationCauseCode<'tcx>>>,
+    code: InternedObligationCauseCode<'tcx>,
 }
 
 // This custom hash function speeds up hashing for `Obligation` deduplication
@@ -114,8 +115,6 @@
     }
 }
 
-const MISC_OBLIGATION_CAUSE_CODE: ObligationCauseCode<'static> = MiscObligation;
-
 impl<'tcx> ObligationCause<'tcx> {
     #[inline]
     pub fn new(
@@ -123,11 +122,7 @@
         body_id: hir::HirId,
         code: ObligationCauseCode<'tcx>,
     ) -> ObligationCause<'tcx> {
-        ObligationCause {
-            span,
-            body_id,
-            code: if code == MISC_OBLIGATION_CAUSE_CODE { None } else { Some(Lrc::new(code)) },
-        }
+        ObligationCause { span, body_id, code: code.into() }
     }
 
     pub fn misc(span: Span, body_id: hir::HirId) -> ObligationCause<'tcx> {
@@ -136,15 +131,12 @@
 
     #[inline(always)]
     pub fn dummy() -> ObligationCause<'tcx> {
-        ObligationCause { span: DUMMY_SP, body_id: hir::CRATE_HIR_ID, code: None }
+        ObligationCause::dummy_with_span(DUMMY_SP)
     }
 
+    #[inline(always)]
     pub fn dummy_with_span(span: Span) -> ObligationCause<'tcx> {
-        ObligationCause { span, body_id: hir::CRATE_HIR_ID, code: None }
-    }
-
-    pub fn make_mut_code(&mut self) -> &mut ObligationCauseCode<'tcx> {
-        Lrc::make_mut(self.code.get_or_insert_with(|| Lrc::new(MISC_OBLIGATION_CAUSE_CODE)))
+        ObligationCause { span, body_id: hir::CRATE_HIR_ID, code: Default::default() }
     }
 
     pub fn span(&self, tcx: TyCtxt<'tcx>) -> Span {
@@ -164,14 +156,37 @@
 
     #[inline]
     pub fn code(&self) -> &ObligationCauseCode<'tcx> {
-        self.code.as_deref().unwrap_or(&MISC_OBLIGATION_CAUSE_CODE)
+        &self.code
     }
 
-    pub fn clone_code(&self) -> Lrc<ObligationCauseCode<'tcx>> {
-        match &self.code {
-            Some(code) => code.clone(),
-            None => Lrc::new(MISC_OBLIGATION_CAUSE_CODE),
-        }
+    pub fn map_code(
+        &mut self,
+        f: impl FnOnce(InternedObligationCauseCode<'tcx>) -> ObligationCauseCode<'tcx>,
+    ) {
+        self.code = f(std::mem::take(&mut self.code)).into();
+    }
+
+    pub fn derived_cause(
+        mut self,
+        parent_trait_pred: ty::PolyTraitPredicate<'tcx>,
+        variant: impl FnOnce(DerivedObligationCause<'tcx>) -> ObligationCauseCode<'tcx>,
+    ) -> ObligationCause<'tcx> {
+        /*!
+         * Creates a cause for obligations that are derived from
+         * `obligation` by a recursive search (e.g., for a builtin
+         * bound, or eventually a `auto trait Foo`). If `obligation`
+         * is itself a derived obligation, this is just a clone, but
+         * otherwise we create a "derived obligation" cause so as to
+         * keep track of the original root obligation for error
+         * reporting.
+         */
+
+        // NOTE(flaper87): As of now, it keeps track of the whole error
+        // chain. Ideally, we should have a way to configure this either
+        // by using -Z verbose or just a CLI argument.
+        self.code =
+            variant(DerivedObligationCause { parent_trait_pred, parent_code: self.code }).into();
+        self
     }
 }
 
@@ -182,6 +197,34 @@
     pub substs: SubstsRef<'tcx>,
 }
 
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Lift, Default)]
+pub struct InternedObligationCauseCode<'tcx> {
+    /// `None` for `ObligationCauseCode::MiscObligation` (a common case, occurs ~60% of
+    /// the time). `Some` otherwise.
+    code: Option<Lrc<ObligationCauseCode<'tcx>>>,
+}
+
+impl<'tcx> ObligationCauseCode<'tcx> {
+    #[inline(always)]
+    fn into(self) -> InternedObligationCauseCode<'tcx> {
+        InternedObligationCauseCode {
+            code: if let ObligationCauseCode::MiscObligation = self {
+                None
+            } else {
+                Some(Lrc::new(self))
+            },
+        }
+    }
+}
+
+impl<'tcx> std::ops::Deref for InternedObligationCauseCode<'tcx> {
+    type Target = ObligationCauseCode<'tcx>;
+
+    fn deref(&self) -> &Self::Target {
+        self.code.as_deref().unwrap_or(&ObligationCauseCode::MiscObligation)
+    }
+}
+
 #[derive(Clone, Debug, PartialEq, Eq, Hash, Lift)]
 pub enum ObligationCauseCode<'tcx> {
     /// Not well classified or should be obvious from the span.
@@ -269,7 +312,7 @@
         /// The node of the function call.
         call_hir_id: hir::HirId,
         /// The obligation introduced by this argument.
-        parent_code: Lrc<ObligationCauseCode<'tcx>>,
+        parent_code: InternedObligationCauseCode<'tcx>,
     },
 
     /// Error derived when matching traits/impls; see ObligationCause for more details
@@ -344,6 +387,9 @@
     /// Return type of this function
     ReturnType,
 
+    /// Opaque return type of this function
+    OpaqueReturnType(Option<(Ty<'tcx>, Span)>),
+
     /// Block implicit return
     BlockTailExpression(hir::HirId),
 
@@ -404,25 +450,27 @@
     pub span: Span,
 }
 
-impl ObligationCauseCode<'_> {
+impl<'tcx> ObligationCauseCode<'tcx> {
     // Return the base obligation, ignoring derived obligations.
     pub fn peel_derives(&self) -> &Self {
         let mut base_cause = self;
-        loop {
-            match base_cause {
-                BuiltinDerivedObligation(DerivedObligationCause { parent_code, .. })
-                | DerivedObligation(DerivedObligationCause { parent_code, .. })
-                | FunctionArgumentObligation { parent_code, .. } => {
-                    base_cause = &parent_code;
-                }
-                ImplDerivedObligation(obligation_cause) => {
-                    base_cause = &*obligation_cause.derived.parent_code;
-                }
-                _ => break,
-            }
+        while let Some((parent_code, _)) = base_cause.parent() {
+            base_cause = parent_code;
         }
         base_cause
     }
+
+    pub fn parent(&self) -> Option<(&Self, Option<ty::PolyTraitPredicate<'tcx>>)> {
+        match self {
+            FunctionArgumentObligation { parent_code, .. } => Some((parent_code, None)),
+            BuiltinDerivedObligation(derived)
+            | DerivedObligation(derived)
+            | ImplDerivedObligation(box ImplDerivedObligationCause { derived, .. }) => {
+                Some((&derived.parent_code, Some(derived.parent_trait_pred)))
+            }
+            _ => None,
+        }
+    }
 }
 
 // `ObligationCauseCode` is used a lot. Make sure it doesn't unintentionally get bigger.
@@ -472,7 +520,7 @@
     pub parent_trait_pred: ty::PolyTraitPredicate<'tcx>,
 
     /// The parent trait had this cause.
-    pub parent_code: Lrc<ObligationCauseCode<'tcx>>,
+    pub parent_code: InternedObligationCauseCode<'tcx>,
 }
 
 #[derive(Clone, Debug, TypeFoldable, Lift)]
@@ -888,7 +936,7 @@
                                  trait objects",
                                 name
                             ),
-                            sugg.to_string(),
+                            sugg,
                             Applicability::MaybeIncorrect,
                         );
                     }
@@ -912,7 +960,7 @@
                         "consider changing method `{}`'s `self` parameter to be `&self`",
                         name
                     ),
-                    "&Self".to_string(),
+                    "&Self",
                     Applicability::MachineApplicable,
                 );
             }
diff --git a/compiler/rustc_middle/src/traits/select.rs b/compiler/rustc_middle/src/traits/select.rs
index ffa70cd..854dd21 100644
--- a/compiler/rustc_middle/src/traits/select.rs
+++ b/compiler/rustc_middle/src/traits/select.rs
@@ -176,6 +176,10 @@
     EvaluatedToOk,
     /// Evaluation successful, but there were unevaluated region obligations.
     EvaluatedToOkModuloRegions,
+    /// Evaluation successful, but need to rerun because opaque types got
+    /// hidden types assigned without it being known whether the opaque types
+    /// are within their defining scope
+    EvaluatedToOkModuloOpaqueTypes,
     /// Evaluation is known to be ambiguous -- it *might* hold for some
     /// assignment of inference variables, but it might not.
     ///
@@ -252,9 +256,11 @@
 
     pub fn may_apply(self) -> bool {
         match self {
-            EvaluatedToOk | EvaluatedToOkModuloRegions | EvaluatedToAmbig | EvaluatedToUnknown => {
-                true
-            }
+            EvaluatedToOkModuloOpaqueTypes
+            | EvaluatedToOk
+            | EvaluatedToOkModuloRegions
+            | EvaluatedToAmbig
+            | EvaluatedToUnknown => true,
 
             EvaluatedToErr | EvaluatedToRecur => false,
         }
@@ -264,7 +270,11 @@
         match self {
             EvaluatedToUnknown | EvaluatedToRecur => true,
 
-            EvaluatedToOk | EvaluatedToOkModuloRegions | EvaluatedToAmbig | EvaluatedToErr => false,
+            EvaluatedToOkModuloOpaqueTypes
+            | EvaluatedToOk
+            | EvaluatedToOkModuloRegions
+            | EvaluatedToAmbig
+            | EvaluatedToErr => false,
         }
     }
 }
diff --git a/compiler/rustc_middle/src/ty/_match.rs b/compiler/rustc_middle/src/ty/_match.rs
index 3243ef2..e6aab30 100644
--- a/compiler/rustc_middle/src/ty/_match.rs
+++ b/compiler/rustc_middle/src/ty/_match.rs
@@ -96,7 +96,7 @@
             return Ok(a);
         }
 
-        match (a.val(), b.val()) {
+        match (a.kind(), b.kind()) {
             (_, ty::ConstKind::Infer(InferConst::Fresh(_))) => {
                 return Ok(a);
             }
diff --git a/compiler/rustc_middle/src/ty/assoc.rs b/compiler/rustc_middle/src/ty/assoc.rs
index 49f8465..2c93af5 100644
--- a/compiler/rustc_middle/src/ty/assoc.rs
+++ b/compiler/rustc_middle/src/ty/assoc.rs
@@ -9,7 +9,7 @@
 
 use super::{TyCtxt, Visibility};
 
-#[derive(Clone, Copy, PartialEq, Eq, Debug, HashStable, Hash)]
+#[derive(Clone, Copy, PartialEq, Eq, Debug, HashStable, Hash, Encodable, Decodable)]
 pub enum AssocItemContainer {
     TraitContainer(DefId),
     ImplContainer(DefId),
@@ -41,7 +41,7 @@
 }
 
 /// Information about an associated item
-#[derive(Copy, Clone, Debug, PartialEq, HashStable, Eq, Hash)]
+#[derive(Copy, Clone, Debug, PartialEq, HashStable, Eq, Hash, Encodable, Decodable)]
 pub struct AssocItem {
     pub def_id: DefId,
     pub name: Symbol,
@@ -81,7 +81,7 @@
     }
 }
 
-#[derive(Copy, Clone, PartialEq, Debug, HashStable, Eq, Hash)]
+#[derive(Copy, Clone, PartialEq, Debug, HashStable, Eq, Hash, Encodable, Decodable)]
 pub enum AssocKind {
     Const,
     Fn,
diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs
index 23c3776..9a36391 100644
--- a/compiler/rustc_middle/src/ty/codec.rs
+++ b/compiler/rustc_middle/src/ty/codec.rs
@@ -15,10 +15,12 @@
 use crate::thir;
 use crate::traits;
 use crate::ty::subst::SubstsRef;
-use crate::ty::{self, AdtDef, Ty, TyCtxt};
+use crate::ty::{self, AdtDef, Ty};
 use rustc_data_structures::fx::FxHashMap;
-use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
+use rustc_middle::ty::TyCtxt;
+use rustc_serialize::{Decodable, Encodable};
 use rustc_span::Span;
+pub use rustc_type_ir::{TyDecoder, TyEncoder};
 use std::hash::Hash;
 use std::intrinsics;
 use std::marker::DiscriminantKind;
@@ -28,13 +30,13 @@
 /// This offset is also chosen so that the first byte is never < 0x80.
 pub const SHORTHAND_OFFSET: usize = 0x80;
 
-pub trait EncodableWithShorthand<'tcx, E: TyEncoder<'tcx>>: Copy + Eq + Hash {
+pub trait EncodableWithShorthand<E: TyEncoder>: Copy + Eq + Hash {
     type Variant: Encodable<E>;
     fn variant(&self) -> &Self::Variant;
 }
 
 #[allow(rustc::usage_of_ty_tykind)]
-impl<'tcx, E: TyEncoder<'tcx>> EncodableWithShorthand<'tcx, E> for Ty<'tcx> {
+impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> EncodableWithShorthand<E> for Ty<'tcx> {
     type Variant = ty::TyKind<'tcx>;
 
     #[inline]
@@ -43,7 +45,7 @@
     }
 }
 
-impl<'tcx, E: TyEncoder<'tcx>> EncodableWithShorthand<'tcx, E> for ty::PredicateKind<'tcx> {
+impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> EncodableWithShorthand<E> for ty::PredicateKind<'tcx> {
     type Variant = ty::PredicateKind<'tcx>;
 
     #[inline]
@@ -52,15 +54,6 @@
     }
 }
 
-pub trait TyEncoder<'tcx>: Encoder {
-    const CLEAR_CROSS_CRATE: bool;
-
-    fn position(&self) -> usize;
-    fn type_shorthands(&mut self) -> &mut FxHashMap<Ty<'tcx>, usize>;
-    fn predicate_shorthands(&mut self) -> &mut FxHashMap<ty::PredicateKind<'tcx>, usize>;
-    fn encode_alloc_id(&mut self, alloc_id: &AllocId) -> Result<(), Self::Error>;
-}
-
 /// Trait for decoding to a reference.
 ///
 /// This is a separate trait from `Decodable` so that we can implement it for
@@ -71,32 +64,29 @@
 ///
 /// `Decodable` can still be implemented in cases where `Decodable` is required
 /// by a trait bound.
-pub trait RefDecodable<'tcx, D: TyDecoder<'tcx>> {
+pub trait RefDecodable<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> {
     fn decode(d: &mut D) -> &'tcx Self;
 }
 
 /// Encode the given value or a previously cached shorthand.
-pub fn encode_with_shorthand<'tcx, E, T, M>(
-    encoder: &mut E,
-    value: &T,
-    cache: M,
-) -> Result<(), E::Error>
+pub fn encode_with_shorthand<'tcx, E, T, M>(encoder: &mut E, value: &T, cache: M)
 where
-    E: TyEncoder<'tcx>,
+    E: TyEncoder<I = TyCtxt<'tcx>>,
     M: for<'b> Fn(&'b mut E) -> &'b mut FxHashMap<T, usize>,
-    T: EncodableWithShorthand<'tcx, E>,
+    T: EncodableWithShorthand<E>,
     // The discriminant and shorthand must have the same size.
     T::Variant: DiscriminantKind<Discriminant = isize>,
 {
     let existing_shorthand = cache(encoder).get(value).copied();
     if let Some(shorthand) = existing_shorthand {
-        return encoder.emit_usize(shorthand);
+        encoder.emit_usize(shorthand);
+        return;
     }
 
     let variant = value.variant();
 
     let start = encoder.position();
-    variant.encode(encoder)?;
+    variant.encode(encoder);
     let len = encoder.position() - start;
 
     // The shorthand encoding uses the same usize as the
@@ -115,123 +105,88 @@
     if leb128_bits >= 64 || (shorthand as u64) < (1 << leb128_bits) {
         cache(encoder).insert(*value, shorthand);
     }
-
-    Ok(())
 }
 
-impl<'tcx, E: TyEncoder<'tcx>> Encodable<E> for Ty<'tcx> {
-    fn encode(&self, e: &mut E) -> Result<(), E::Error> {
-        encode_with_shorthand(e, self, TyEncoder::type_shorthands)
+impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E> for Ty<'tcx> {
+    fn encode(&self, e: &mut E) {
+        encode_with_shorthand(e, self, TyEncoder::type_shorthands);
     }
 }
 
-impl<'tcx, E: TyEncoder<'tcx>> Encodable<E> for ty::Binder<'tcx, ty::PredicateKind<'tcx>> {
-    fn encode(&self, e: &mut E) -> Result<(), E::Error> {
-        self.bound_vars().encode(e)?;
-        encode_with_shorthand(e, &self.skip_binder(), TyEncoder::predicate_shorthands)
+impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E>
+    for ty::Binder<'tcx, ty::PredicateKind<'tcx>>
+{
+    fn encode(&self, e: &mut E) {
+        self.bound_vars().encode(e);
+        encode_with_shorthand(e, &self.skip_binder(), TyEncoder::predicate_shorthands);
     }
 }
 
-impl<'tcx, E: TyEncoder<'tcx>> Encodable<E> for ty::Predicate<'tcx> {
-    fn encode(&self, e: &mut E) -> Result<(), E::Error> {
-        self.kind().encode(e)
+impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E> for ty::Predicate<'tcx> {
+    fn encode(&self, e: &mut E) {
+        self.kind().encode(e);
     }
 }
 
-impl<'tcx, E: TyEncoder<'tcx>> Encodable<E> for ty::Region<'tcx> {
-    fn encode(&self, e: &mut E) -> Result<(), E::Error> {
-        self.kind().encode(e)
+impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E> for ty::Region<'tcx> {
+    fn encode(&self, e: &mut E) {
+        self.kind().encode(e);
     }
 }
 
-impl<'tcx, E: TyEncoder<'tcx>> Encodable<E> for ty::Const<'tcx> {
-    fn encode(&self, e: &mut E) -> Result<(), E::Error> {
-        self.0.0.encode(e)
+impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E> for ty::Const<'tcx> {
+    fn encode(&self, e: &mut E) {
+        self.0.0.encode(e);
     }
 }
 
-impl<'tcx, E: TyEncoder<'tcx>> Encodable<E> for ConstAllocation<'tcx> {
-    fn encode(&self, e: &mut E) -> Result<(), E::Error> {
+impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E> for ConstAllocation<'tcx> {
+    fn encode(&self, e: &mut E) {
         self.inner().encode(e)
     }
 }
 
-impl<'tcx, E: TyEncoder<'tcx>> Encodable<E> for AdtDef<'tcx> {
-    fn encode(&self, e: &mut E) -> Result<(), E::Error> {
+impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E> for AdtDef<'tcx> {
+    fn encode(&self, e: &mut E) {
         self.0.0.encode(e)
     }
 }
 
-impl<'tcx, E: TyEncoder<'tcx>> Encodable<E> for AllocId {
-    fn encode(&self, e: &mut E) -> Result<(), E::Error> {
+impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E> for AllocId {
+    fn encode(&self, e: &mut E) {
         e.encode_alloc_id(self)
     }
 }
 
-macro_rules! encodable_via_deref {
-    ($($t:ty),+) => {
-        $(impl<'tcx, E: TyEncoder<'tcx>> Encodable<E> for $t {
-            fn encode(&self, e: &mut E) -> Result<(), E::Error> {
-                (**self).encode(e)
-            }
-        })*
-    }
-}
-
-encodable_via_deref! {
-    &'tcx ty::TypeckResults<'tcx>,
-    &'tcx traits::ImplSource<'tcx, ()>,
-    &'tcx mir::Body<'tcx>,
-    &'tcx mir::UnsafetyCheckResult,
-    &'tcx mir::BorrowCheckResult<'tcx>,
-    &'tcx mir::coverage::CodeRegion
-}
-
-pub trait TyDecoder<'tcx>: Decoder {
-    const CLEAR_CROSS_CRATE: bool;
-
-    fn tcx(&self) -> TyCtxt<'tcx>;
-
-    fn peek_byte(&self) -> u8;
-
-    fn position(&self) -> usize;
-
-    fn cached_ty_for_shorthand<F>(&mut self, shorthand: usize, or_insert_with: F) -> Ty<'tcx>
-    where
-        F: FnOnce(&mut Self) -> Ty<'tcx>;
-
-    fn with_position<F, R>(&mut self, pos: usize, f: F) -> R
-    where
-        F: FnOnce(&mut Self) -> R;
-
-    fn positioned_at_shorthand(&self) -> bool {
-        (self.peek_byte() & (SHORTHAND_OFFSET as u8)) != 0
-    }
-
-    fn decode_alloc_id(&mut self) -> AllocId;
-}
-
 #[inline]
-fn decode_arena_allocable<'tcx, D, T: ArenaAllocatable<'tcx> + Decodable<D>>(
+fn decode_arena_allocable<
+    'tcx,
+    D: TyDecoder<I = TyCtxt<'tcx>>,
+    T: ArenaAllocatable<'tcx> + Decodable<D>,
+>(
     decoder: &mut D,
 ) -> &'tcx T
 where
-    D: TyDecoder<'tcx>,
+    D: TyDecoder,
 {
-    decoder.tcx().arena.alloc(Decodable::decode(decoder))
+    decoder.interner().arena.alloc(Decodable::decode(decoder))
 }
 
 #[inline]
-fn decode_arena_allocable_slice<'tcx, D, T: ArenaAllocatable<'tcx> + Decodable<D>>(
+fn decode_arena_allocable_slice<
+    'tcx,
+    D: TyDecoder<I = TyCtxt<'tcx>>,
+    T: ArenaAllocatable<'tcx> + Decodable<D>,
+>(
     decoder: &mut D,
 ) -> &'tcx [T]
 where
-    D: TyDecoder<'tcx>,
+    D: TyDecoder,
 {
-    decoder.tcx().arena.alloc_from_iter(<Vec<T> as Decodable<D>>::decode(decoder))
+    decoder.interner().arena.alloc_from_iter(<Vec<T> as Decodable<D>>::decode(decoder))
 }
 
-impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for Ty<'tcx> {
+impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for Ty<'tcx> {
     #[allow(rustc::usage_of_ty_tykind)]
     fn decode(decoder: &mut D) -> Ty<'tcx> {
         // Handle shorthands first, if we have a usize > 0x80.
@@ -244,13 +199,15 @@
                 decoder.with_position(shorthand, Ty::decode)
             })
         } else {
-            let tcx = decoder.tcx();
-            tcx.mk_ty(ty::TyKind::decode(decoder))
+            let tcx = decoder.interner();
+            tcx.mk_ty(rustc_type_ir::TyKind::decode(decoder))
         }
     }
 }
 
-impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for ty::Binder<'tcx, ty::PredicateKind<'tcx>> {
+impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D>
+    for ty::Binder<'tcx, ty::PredicateKind<'tcx>>
+{
     fn decode(decoder: &mut D) -> ty::Binder<'tcx, ty::PredicateKind<'tcx>> {
         let bound_vars = Decodable::decode(decoder);
         // Handle shorthands first, if we have a usize > 0x80.
@@ -269,64 +226,64 @@
     }
 }
 
-impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for ty::Predicate<'tcx> {
+impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for ty::Predicate<'tcx> {
     fn decode(decoder: &mut D) -> ty::Predicate<'tcx> {
         let predicate_kind = Decodable::decode(decoder);
-        decoder.tcx().mk_predicate(predicate_kind)
+        decoder.interner().mk_predicate(predicate_kind)
     }
 }
 
-impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for SubstsRef<'tcx> {
+impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for SubstsRef<'tcx> {
     fn decode(decoder: &mut D) -> Self {
         let len = decoder.read_usize();
-        let tcx = decoder.tcx();
+        let tcx = decoder.interner();
         tcx.mk_substs(
             (0..len).map::<ty::subst::GenericArg<'tcx>, _>(|_| Decodable::decode(decoder)),
         )
     }
 }
 
-impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for mir::Place<'tcx> {
+impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for mir::Place<'tcx> {
     fn decode(decoder: &mut D) -> Self {
         let local: mir::Local = Decodable::decode(decoder);
         let len = decoder.read_usize();
-        let projection = decoder.tcx().mk_place_elems(
+        let projection = decoder.interner().mk_place_elems(
             (0..len).map::<mir::PlaceElem<'tcx>, _>(|_| Decodable::decode(decoder)),
         );
         mir::Place { local, projection }
     }
 }
 
-impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for ty::Region<'tcx> {
+impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for ty::Region<'tcx> {
     fn decode(decoder: &mut D) -> Self {
-        decoder.tcx().mk_region(Decodable::decode(decoder))
+        decoder.interner().mk_region(Decodable::decode(decoder))
     }
 }
 
-impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for CanonicalVarInfos<'tcx> {
+impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for CanonicalVarInfos<'tcx> {
     fn decode(decoder: &mut D) -> Self {
         let len = decoder.read_usize();
         let interned: Vec<CanonicalVarInfo<'tcx>> =
             (0..len).map(|_| Decodable::decode(decoder)).collect();
-        decoder.tcx().intern_canonical_var_infos(interned.as_slice())
+        decoder.interner().intern_canonical_var_infos(interned.as_slice())
     }
 }
 
-impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for AllocId {
+impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for AllocId {
     fn decode(decoder: &mut D) -> Self {
         decoder.decode_alloc_id()
     }
 }
 
-impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for ty::SymbolName<'tcx> {
+impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for ty::SymbolName<'tcx> {
     fn decode(decoder: &mut D) -> Self {
-        ty::SymbolName::new(decoder.tcx(), &decoder.read_str())
+        ty::SymbolName::new(decoder.interner(), &decoder.read_str())
     }
 }
 
 macro_rules! impl_decodable_via_ref {
     ($($t:ty),+) => {
-        $(impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for $t {
+        $(impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for $t {
             fn decode(decoder: &mut D) -> Self {
                 RefDecodable::decode(decoder)
             }
@@ -334,78 +291,86 @@
     }
 }
 
-impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for ty::List<Ty<'tcx>> {
+impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> for ty::List<Ty<'tcx>> {
     fn decode(decoder: &mut D) -> &'tcx Self {
         let len = decoder.read_usize();
-        decoder.tcx().mk_type_list((0..len).map::<Ty<'tcx>, _>(|_| Decodable::decode(decoder)))
+        decoder.interner().mk_type_list((0..len).map::<Ty<'tcx>, _>(|_| Decodable::decode(decoder)))
     }
 }
 
-impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D>
+impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D>
     for ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>>
 {
     fn decode(decoder: &mut D) -> &'tcx Self {
         let len = decoder.read_usize();
-        decoder.tcx().mk_poly_existential_predicates(
+        decoder.interner().mk_poly_existential_predicates(
             (0..len).map::<ty::Binder<'tcx, _>, _>(|_| Decodable::decode(decoder)),
         )
     }
 }
 
-impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for ty::Const<'tcx> {
+impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for ty::Const<'tcx> {
     fn decode(decoder: &mut D) -> Self {
-        decoder.tcx().mk_const(Decodable::decode(decoder))
+        decoder.interner().mk_const(Decodable::decode(decoder))
     }
 }
 
-impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [ty::ValTree<'tcx>] {
+impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> for [ty::ValTree<'tcx>] {
     fn decode(decoder: &mut D) -> &'tcx Self {
-        decoder.tcx().arena.alloc_from_iter(
+        decoder.interner().arena.alloc_from_iter(
             (0..decoder.read_usize()).map(|_| Decodable::decode(decoder)).collect::<Vec<_>>(),
         )
     }
 }
 
-impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for ConstAllocation<'tcx> {
+impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for ConstAllocation<'tcx> {
     fn decode(decoder: &mut D) -> Self {
-        decoder.tcx().intern_const_alloc(Decodable::decode(decoder))
+        decoder.interner().intern_const_alloc(Decodable::decode(decoder))
     }
 }
 
-impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for AdtDef<'tcx> {
+impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for AdtDef<'tcx> {
     fn decode(decoder: &mut D) -> Self {
-        decoder.tcx().intern_adt_def(Decodable::decode(decoder))
+        decoder.interner().intern_adt_def(Decodable::decode(decoder))
     }
 }
 
-impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [(ty::Predicate<'tcx>, Span)] {
+impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D>
+    for [(ty::Predicate<'tcx>, Span)]
+{
     fn decode(decoder: &mut D) -> &'tcx Self {
-        decoder.tcx().arena.alloc_from_iter(
+        decoder.interner().arena.alloc_from_iter(
             (0..decoder.read_usize()).map(|_| Decodable::decode(decoder)).collect::<Vec<_>>(),
         )
     }
 }
 
-impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [thir::abstract_const::Node<'tcx>] {
+impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D>
+    for [thir::abstract_const::Node<'tcx>]
+{
     fn decode(decoder: &mut D) -> &'tcx Self {
-        decoder.tcx().arena.alloc_from_iter(
+        decoder.interner().arena.alloc_from_iter(
             (0..decoder.read_usize()).map(|_| Decodable::decode(decoder)).collect::<Vec<_>>(),
         )
     }
 }
 
-impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [thir::abstract_const::NodeId] {
+impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D>
+    for [thir::abstract_const::NodeId]
+{
     fn decode(decoder: &mut D) -> &'tcx Self {
-        decoder.tcx().arena.alloc_from_iter(
+        decoder.interner().arena.alloc_from_iter(
             (0..decoder.read_usize()).map(|_| Decodable::decode(decoder)).collect::<Vec<_>>(),
         )
     }
 }
 
-impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for ty::List<ty::BoundVariableKind> {
+impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D>
+    for ty::List<ty::BoundVariableKind>
+{
     fn decode(decoder: &mut D) -> &'tcx Self {
         let len = decoder.read_usize();
-        decoder.tcx().mk_bound_variable_kinds(
+        decoder.interner().mk_bound_variable_kinds(
             (0..len).map::<ty::BoundVariableKind, _>(|_| Decodable::decode(decoder)),
         )
     }
@@ -439,14 +404,14 @@
     ([]$args:tt) => {};
     ([decode $(, $attrs:ident)*]
      [$name:ident: $ty:ty]) => {
-        impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for $ty {
+        impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> for $ty {
             #[inline]
             fn decode(decoder: &mut D) -> &'tcx Self {
                 decode_arena_allocable(decoder)
             }
         }
 
-        impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [$ty] {
+        impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> for [$ty] {
             #[inline]
             fn decode(decoder: &mut D) -> &'tcx Self {
                 decode_arena_allocable_slice(decoder)
@@ -466,6 +431,33 @@
 rustc_hir::arena_types!(impl_arena_allocatable_decoders);
 arena_types!(impl_arena_allocatable_decoders);
 
+macro_rules! impl_arena_copy_decoder {
+    (<$tcx:tt> $($ty:ty,)*) => {
+        $(impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> for $ty {
+            #[inline]
+            fn decode(decoder: &mut D) -> &'tcx Self {
+                decoder.interner().arena.alloc(Decodable::decode(decoder))
+            }
+        }
+
+        impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> for [$ty] {
+            #[inline]
+            fn decode(decoder: &mut D) -> &'tcx Self {
+                decoder.interner().arena.alloc_from_iter(<Vec<_> as Decodable<D>>::decode(decoder))
+            }
+        })*
+    };
+}
+
+impl_arena_copy_decoder! {<'tcx>
+    Span,
+    rustc_span::symbol::Ident,
+    ty::Variance,
+    rustc_span::def_id::DefId,
+    rustc_span::def_id::LocalDefId,
+    (rustc_middle::middle::exported_symbols::ExportedSymbol<'tcx>, rustc_middle::middle::exported_symbols::SymbolExportInfo),
+}
+
 #[macro_export]
 macro_rules! implement_ty_decoder {
     ($DecoderName:ident <$($typaram:tt),*>) => {
@@ -510,13 +502,13 @@
 macro_rules! impl_binder_encode_decode {
     ($($t:ty),+ $(,)?) => {
         $(
-            impl<'tcx, E: TyEncoder<'tcx>> Encodable<E> for ty::Binder<'tcx, $t> {
-                fn encode(&self, e: &mut E) -> Result<(), E::Error> {
-                    self.bound_vars().encode(e)?;
-                    self.as_ref().skip_binder().encode(e)
+            impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E> for ty::Binder<'tcx, $t> {
+                fn encode(&self, e: &mut E) {
+                    self.bound_vars().encode(e);
+                    self.as_ref().skip_binder().encode(e);
                 }
             }
-            impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for ty::Binder<'tcx, $t> {
+            impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for ty::Binder<'tcx, $t> {
                 fn decode(decoder: &mut D) -> Self {
                     let bound_vars = Decodable::decode(decoder);
                     ty::Binder::bind_with_vars(Decodable::decode(decoder), bound_vars)
diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs
index 7af7eb4..bc52259 100644
--- a/compiler/rustc_middle/src/ty/consts.rs
+++ b/compiler/rustc_middle/src/ty/consts.rs
@@ -1,5 +1,5 @@
-use crate::mir::interpret::ConstValue;
-use crate::mir::interpret::{LitToConstInput, Scalar};
+use crate::mir::interpret::LitToConstInput;
+use crate::mir::ConstantKind;
 use crate::ty::{
     self, InlineConstSubsts, InlineConstSubstsParts, InternalSubsts, ParamEnv, ParamEnvAnd, Ty,
     TyCtxt, TypeFoldable,
@@ -29,7 +29,7 @@
         // This reflects what `Const` looked liked before `Interned` was
         // introduced. We print it like this to avoid having to update expected
         // output in a lot of tests.
-        write!(f, "Const {{ ty: {:?}, val: {:?} }}", self.ty(), self.val())
+        write!(f, "Const {{ ty: {:?}, kind: {:?} }}", self.ty(), self.kind())
     }
 }
 
@@ -37,7 +37,7 @@
 #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, HashStable, TyEncodable, TyDecodable)]
 pub struct ConstS<'tcx> {
     pub ty: Ty<'tcx>,
-    pub val: ConstKind<'tcx>,
+    pub kind: ConstKind<'tcx>,
 }
 
 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
@@ -50,8 +50,8 @@
     }
 
     #[inline]
-    pub fn val(self) -> ConstKind<'tcx> {
-        self.0.val
+    pub fn kind(self) -> ConstKind<'tcx> {
+        self.0.kind
     }
 
     /// Literals and const generic parameters are eagerly converted to a constant, everything else
@@ -83,7 +83,7 @@
         match Self::try_eval_lit_or_param(tcx, ty, expr) {
             Some(v) => v,
             None => tcx.mk_const(ty::ConstS {
-                val: ty::ConstKind::Unevaluated(ty::Unevaluated {
+                kind: ty::ConstKind::Unevaluated(ty::Unevaluated {
                     def: def.to_global(),
                     substs: InternalSubsts::identity_for_item(tcx, def.did.to_def_id()),
                     promoted: None,
@@ -145,7 +145,7 @@
                 let index = generics.param_def_id_to_index[&def_id];
                 let name = tcx.hir().name(hir_id);
                 Some(tcx.mk_const(ty::ConstS {
-                    val: ty::ConstKind::Param(ty::ParamConst::new(index, name)),
+                    kind: ty::ConstKind::Param(ty::ParamConst::new(index, name)),
                     ty,
                 }))
             }
@@ -180,7 +180,7 @@
                     InlineConstSubsts::new(tcx, InlineConstSubstsParts { parent_substs, ty })
                         .substs;
                 tcx.mk_const(ty::ConstS {
-                    val: ty::ConstKind::Unevaluated(ty::Unevaluated {
+                    kind: ty::ConstKind::Unevaluated(ty::Unevaluated {
                         def: ty::WithOptConstParam::unknown(def_id).to_global(),
                         substs,
                         promoted: None,
@@ -195,14 +195,21 @@
 
     /// Interns the given value as a constant.
     #[inline]
-    pub fn from_value(tcx: TyCtxt<'tcx>, val: ConstValue<'tcx>, ty: Ty<'tcx>) -> Self {
-        tcx.mk_const(ConstS { val: ConstKind::Value(val), ty })
+    pub fn from_value(tcx: TyCtxt<'tcx>, val: ty::ValTree<'tcx>, ty: Ty<'tcx>) -> Self {
+        tcx.mk_const(ConstS { kind: ConstKind::Value(val), ty })
     }
 
-    #[inline]
-    /// Interns the given scalar as a constant.
-    pub fn from_scalar(tcx: TyCtxt<'tcx>, val: Scalar, ty: Ty<'tcx>) -> Self {
-        Self::from_value(tcx, ConstValue::Scalar(val), ty)
+    /// Panics if self.kind != ty::ConstKind::Value
+    pub fn to_valtree(self) -> ty::ValTree<'tcx> {
+        match self.kind() {
+            ty::ConstKind::Value(valtree) => valtree,
+            _ => bug!("expected ConstKind::Value"),
+        }
+    }
+
+    pub fn from_scalar_int(tcx: TyCtxt<'tcx>, i: ScalarInt, ty: Ty<'tcx>) -> Self {
+        let valtree = ty::ValTree::from_scalar_int(i);
+        Self::from_value(tcx, valtree, ty)
     }
 
     #[inline]
@@ -212,13 +219,14 @@
             .layout_of(ty)
             .unwrap_or_else(|e| panic!("could not compute layout for {:?}: {:?}", ty, e))
             .size;
-        Self::from_scalar(tcx, Scalar::from_uint(bits, size), ty.value)
+        Self::from_scalar_int(tcx, ScalarInt::try_from_uint(bits, size).unwrap(), ty.value)
     }
 
     #[inline]
     /// Creates an interned zst constant.
     pub fn zero_sized(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Self {
-        Self::from_scalar(tcx, Scalar::ZST, ty)
+        let valtree = ty::ValTree::zst();
+        Self::from_value(tcx, valtree, ty)
     }
 
     #[inline]
@@ -246,34 +254,49 @@
         assert_eq!(self.ty(), ty);
         let size = tcx.layout_of(param_env.with_reveal_all_normalized(tcx).and(ty)).ok()?.size;
         // if `ty` does not depend on generic parameters, use an empty param_env
-        self.val().eval(tcx, param_env).try_to_bits(size)
+        self.kind().eval(tcx, param_env).try_to_bits(size)
     }
 
     #[inline]
     pub fn try_eval_bool(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Option<bool> {
-        self.val().eval(tcx, param_env).try_to_bool()
+        self.kind().eval(tcx, param_env).try_to_bool()
     }
 
     #[inline]
     pub fn try_eval_usize(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Option<u64> {
-        self.val().eval(tcx, param_env).try_to_machine_usize(tcx)
+        self.kind().eval(tcx, param_env).try_to_machine_usize(tcx)
     }
 
     #[inline]
     /// Tries to evaluate the constant if it is `Unevaluated`. If that doesn't succeed, return the
     /// unevaluated constant.
     pub fn eval(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Const<'tcx> {
-        if let Some(val) = self.val().try_eval(tcx, param_env) {
+        if let Some(val) = self.kind().try_eval_for_typeck(tcx, param_env) {
             match val {
                 Ok(val) => Const::from_value(tcx, val, self.ty()),
                 Err(ErrorGuaranteed { .. }) => tcx.const_error(self.ty()),
             }
         } else {
+            // Either the constant isn't evaluatable or ValTree creation failed.
             self
         }
     }
 
     #[inline]
+    /// Tries to evaluate the constant if it is `Unevaluated` and creates a ConstValue if the
+    /// evaluation succeeds. If it doesn't succeed, returns the unevaluated constant.
+    pub fn eval_for_mir(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> ConstantKind<'tcx> {
+        if let Some(val) = self.kind().try_eval_for_mir(tcx, param_env) {
+            match val {
+                Ok(const_val) => ConstantKind::from_value(const_val, self.ty()),
+                Err(ErrorGuaranteed { .. }) => ConstantKind::Ty(tcx.const_error(self.ty())),
+            }
+        } else {
+            ConstantKind::Ty(self)
+        }
+    }
+
+    #[inline]
     /// Panics if the value cannot be evaluated or doesn't contain a valid integer of the given type.
     pub fn eval_bits(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, ty: Ty<'tcx>) -> u128 {
         self.try_eval_bits(tcx, param_env, ty)
diff --git a/compiler/rustc_middle/src/ty/consts/int.rs b/compiler/rustc_middle/src/ty/consts/int.rs
index a3ce674..51e51a6 100644
--- a/compiler/rustc_middle/src/ty/consts/int.rs
+++ b/compiler/rustc_middle/src/ty/consts/int.rs
@@ -140,9 +140,9 @@
 }
 
 impl<S: Encoder> Encodable<S> for ScalarInt {
-    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
-        s.emit_u128(self.data)?;
-        s.emit_u8(self.size)
+    fn encode(&self, s: &mut S) {
+        s.emit_u128(self.data);
+        s.emit_u8(self.size);
     }
 }
 
diff --git a/compiler/rustc_middle/src/ty/consts/kind.rs b/compiler/rustc_middle/src/ty/consts/kind.rs
index 35d286d2..10d0306 100644
--- a/compiler/rustc_middle/src/ty/consts/kind.rs
+++ b/compiler/rustc_middle/src/ty/consts/kind.rs
@@ -63,7 +63,7 @@
     Unevaluated(Unevaluated<'tcx>),
 
     /// Used to hold computed value.
-    Value(ConstValue<'tcx>),
+    Value(ty::ValTree<'tcx>),
 
     /// A placeholder for a const which could not be computed; this is
     /// propagated to avoid useless error messages.
@@ -75,7 +75,7 @@
 
 impl<'tcx> ConstKind<'tcx> {
     #[inline]
-    pub fn try_to_value(self) -> Option<ConstValue<'tcx>> {
+    pub fn try_to_value(self) -> Option<ty::ValTree<'tcx>> {
         if let ConstKind::Value(val) = self { Some(val) } else { None }
     }
 
@@ -86,7 +86,7 @@
 
     #[inline]
     pub fn try_to_scalar_int(self) -> Option<ScalarInt> {
-        Some(self.try_to_value()?.try_to_scalar()?.assert_int())
+        self.try_to_value()?.try_to_scalar_int()
     }
 
     #[inline]
@@ -115,23 +115,65 @@
     Fresh(u32),
 }
 
+enum EvalMode {
+    Typeck,
+    Mir,
+}
+
+enum EvalResult<'tcx> {
+    ValTree(ty::ValTree<'tcx>),
+    ConstVal(ConstValue<'tcx>),
+}
+
 impl<'tcx> ConstKind<'tcx> {
     #[inline]
     /// Tries to evaluate the constant if it is `Unevaluated`. If that doesn't succeed, return the
     /// unevaluated constant.
     pub fn eval(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Self {
-        self.try_eval(tcx, param_env).and_then(Result::ok).map_or(self, ConstKind::Value)
+        self.try_eval_for_typeck(tcx, param_env).and_then(Result::ok).map_or(self, ConstKind::Value)
     }
 
     #[inline]
     /// Tries to evaluate the constant if it is `Unevaluated`. If that isn't possible or necessary
     /// return `None`.
     // FIXME(@lcnr): Completely rework the evaluation/normalization system for `ty::Const` once valtrees are merged.
-    pub fn try_eval(
+    pub fn try_eval_for_mir(
         self,
         tcx: TyCtxt<'tcx>,
         param_env: ParamEnv<'tcx>,
     ) -> Option<Result<ConstValue<'tcx>, ErrorGuaranteed>> {
+        match self.try_eval_inner(tcx, param_env, EvalMode::Mir) {
+            Some(Ok(EvalResult::ValTree(_))) => unreachable!(),
+            Some(Ok(EvalResult::ConstVal(v))) => Some(Ok(v)),
+            Some(Err(e)) => Some(Err(e)),
+            None => None,
+        }
+    }
+
+    #[inline]
+    /// Tries to evaluate the constant if it is `Unevaluated`. If that isn't possible or necessary
+    /// return `None`.
+    // FIXME(@lcnr): Completely rework the evaluation/normalization system for `ty::Const` once valtrees are merged.
+    pub fn try_eval_for_typeck(
+        self,
+        tcx: TyCtxt<'tcx>,
+        param_env: ParamEnv<'tcx>,
+    ) -> Option<Result<ty::ValTree<'tcx>, ErrorGuaranteed>> {
+        match self.try_eval_inner(tcx, param_env, EvalMode::Typeck) {
+            Some(Ok(EvalResult::ValTree(v))) => Some(Ok(v)),
+            Some(Ok(EvalResult::ConstVal(_))) => unreachable!(),
+            Some(Err(e)) => Some(Err(e)),
+            None => None,
+        }
+    }
+
+    #[inline]
+    fn try_eval_inner(
+        self,
+        tcx: TyCtxt<'tcx>,
+        param_env: ParamEnv<'tcx>,
+        eval_mode: EvalMode,
+    ) -> Option<Result<EvalResult<'tcx>, ErrorGuaranteed>> {
         if let ConstKind::Unevaluated(unevaluated) = self {
             use crate::mir::interpret::ErrorHandled;
 
@@ -166,14 +208,29 @@
             let (param_env, unevaluated) = param_env_and.into_parts();
             // try to resolve e.g. associated constants to their definition on an impl, and then
             // evaluate the const.
-            match tcx.const_eval_resolve(param_env, unevaluated, None) {
-                // NOTE(eddyb) `val` contains no lifetimes/types/consts,
-                // and we use the original type, so nothing from `substs`
-                // (which may be identity substs, see above),
-                // can leak through `val` into the const we return.
-                Ok(val) => Some(Ok(val)),
-                Err(ErrorHandled::TooGeneric | ErrorHandled::Linted) => None,
-                Err(ErrorHandled::Reported(e)) => Some(Err(e)),
+            match eval_mode {
+                EvalMode::Typeck => {
+                    match tcx.const_eval_resolve_for_typeck(param_env, unevaluated, None) {
+                        // NOTE(eddyb) `val` contains no lifetimes/types/consts,
+                        // and we use the original type, so nothing from `substs`
+                        // (which may be identity substs, see above),
+                        // can leak through `val` into the const we return.
+                        Ok(val) => Some(Ok(EvalResult::ValTree(val?))),
+                        Err(ErrorHandled::TooGeneric | ErrorHandled::Linted) => None,
+                        Err(ErrorHandled::Reported(e)) => Some(Err(e)),
+                    }
+                }
+                EvalMode::Mir => {
+                    match tcx.const_eval_resolve(param_env, unevaluated, None) {
+                        // NOTE(eddyb) `val` contains no lifetimes/types/consts,
+                        // and we use the original type, so nothing from `substs`
+                        // (which may be identity substs, see above),
+                        // can leak through `val` into the const we return.
+                        Ok(val) => Some(Ok(EvalResult::ConstVal(val))),
+                        Err(ErrorHandled::TooGeneric | ErrorHandled::Linted) => None,
+                        Err(ErrorHandled::Reported(e)) => Some(Err(e)),
+                    }
+                }
             }
         } else {
             None
diff --git a/compiler/rustc_middle/src/ty/consts/valtree.rs b/compiler/rustc_middle/src/ty/consts/valtree.rs
index 418848f..973dc3d 100644
--- a/compiler/rustc_middle/src/ty/consts/valtree.rs
+++ b/compiler/rustc_middle/src/ty/consts/valtree.rs
@@ -1,4 +1,6 @@
 use super::ScalarInt;
+use crate::mir::interpret::{AllocId, Scalar};
+use crate::ty::{self, Ty, TyCtxt};
 use rustc_macros::{HashStable, TyDecodable, TyEncodable};
 
 #[derive(Copy, Clone, Debug, Hash, TyEncodable, TyDecodable, Eq, PartialEq, Ord, PartialOrd)]
@@ -50,4 +52,61 @@
             _ => bug!("expected branch, got {:?}", self),
         }
     }
+
+    pub fn from_raw_bytes<'a>(tcx: TyCtxt<'tcx>, bytes: &'a [u8]) -> Self {
+        let branches = bytes.iter().map(|b| Self::Leaf(ScalarInt::from(*b)));
+        let interned = tcx.arena.alloc_from_iter(branches);
+
+        Self::Branch(interned)
+    }
+
+    pub fn from_scalar_int(i: ScalarInt) -> Self {
+        Self::Leaf(i)
+    }
+
+    pub fn try_to_scalar(self) -> Option<Scalar<AllocId>> {
+        self.try_to_scalar_int().map(Scalar::Int)
+    }
+
+    pub fn try_to_scalar_int(self) -> Option<ScalarInt> {
+        match self {
+            Self::Leaf(s) => Some(s),
+            Self::Branch(_) => None,
+        }
+    }
+
+    pub fn try_to_machine_usize(self, tcx: TyCtxt<'tcx>) -> Option<u64> {
+        self.try_to_scalar_int().map(|s| s.try_to_machine_usize(tcx).ok()).flatten()
+    }
+
+    /// Get the values inside the ValTree as a slice of bytes. This only works for
+    /// constants with types &str and &[u8].
+    pub fn try_to_raw_bytes(self, tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option<&'tcx [u8]> {
+        match ty.kind() {
+            ty::Ref(_, inner_ty, _) => match inner_ty.kind() {
+                ty::Str => {
+                    let leafs = self
+                        .unwrap_branch()
+                        .into_iter()
+                        .map(|v| v.unwrap_leaf().try_to_u8().unwrap())
+                        .collect::<Vec<_>>();
+
+                    return Some(tcx.arena.alloc_from_iter(leafs.into_iter()));
+                }
+                ty::Slice(slice_ty) if *slice_ty == tcx.types.u8 => {
+                    let leafs = self
+                        .unwrap_branch()
+                        .into_iter()
+                        .map(|v| v.unwrap_leaf().try_to_u8().unwrap())
+                        .collect::<Vec<_>>();
+
+                    return Some(tcx.arena.alloc_from_iter(leafs.into_iter()));
+                }
+                _ => {}
+            },
+            _ => {}
+        }
+
+        None
+    }
 }
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 1616b75..c3df9a6 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -6,9 +6,9 @@
 use crate::infer::canonical::{Canonical, CanonicalVarInfo, CanonicalVarInfos};
 use crate::lint::{struct_lint_level, LintDiagnosticBuilder, LintLevelSource};
 use crate::middle::codegen_fn_attrs::CodegenFnAttrs;
-use crate::middle::resolve_lifetime::{self, LifetimeScopeForPath};
+use crate::middle::resolve_lifetime;
 use crate::middle::stability;
-use crate::mir::interpret::{self, Allocation, ConstAllocation, ConstValue, Scalar};
+use crate::mir::interpret::{self, Allocation, ConstAllocation};
 use crate::mir::{
     Body, BorrowCheckResult, Field, Local, Place, PlaceElem, ProjectionKind, Promoted,
 };
@@ -16,7 +16,6 @@
 use crate::traits;
 use crate::ty::query::{self, TyCtxtAt};
 use crate::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst, SubstsRef, UserSubsts};
-use crate::ty::TyKind::*;
 use crate::ty::{
     self, AdtDef, AdtDefData, AdtKind, Binder, BindingMode, BoundVar, CanonicalPolyFnSig,
     ClosureSizeProfileData, Const, ConstS, ConstVid, DefIdTree, ExistentialPredicate, FloatTy,
@@ -50,7 +49,8 @@
 use rustc_middle::mir::FakeReadCause;
 use rustc_query_system::ich::StableHashingContext;
 use rustc_serialize::opaque::{FileEncodeResult, FileEncoder};
-use rustc_session::config::{BorrowckMode, CrateType, OutputFilenames};
+use rustc_session::config::{CrateType, OutputFilenames};
+use rustc_session::cstore::CrateStoreDyn;
 use rustc_session::lint::{Level, Lint};
 use rustc_session::Limit;
 use rustc_session::Session;
@@ -60,9 +60,9 @@
 use rustc_span::{Span, DUMMY_SP};
 use rustc_target::abi::{Layout, LayoutS, TargetDataLayout, VariantIdx};
 use rustc_target::spec::abi;
+use rustc_type_ir::sty::TyKind::*;
+use rustc_type_ir::{InternAs, InternIteratorElement, Interner, TypeFlags};
 
-use rustc_type_ir::TypeFlags;
-use smallvec::SmallVec;
 use std::any::Any;
 use std::borrow::Borrow;
 use std::cmp::Ordering;
@@ -74,6 +74,8 @@
 use std::ops::{Bound, Deref};
 use std::sync::Arc;
 
+use super::{ImplPolarity, RvalueScopes};
+
 pub trait OnDiskCache<'tcx>: rustc_data_structures::sync::Sync {
     /// Creates a new `OnDiskCache` instance from the serialized data in `data`.
     fn new(sess: &'tcx Session, data: Mmap, start_pos: usize) -> Self
@@ -86,7 +88,38 @@
 
     fn drop_serialized_data(&self, tcx: TyCtxt<'tcx>);
 
-    fn serialize(&self, tcx: TyCtxt<'tcx>, encoder: &mut FileEncoder) -> FileEncodeResult;
+    fn serialize(&self, tcx: TyCtxt<'tcx>, encoder: FileEncoder) -> FileEncodeResult;
+}
+
+#[allow(rustc::usage_of_ty_tykind)]
+impl<'tcx> Interner for TyCtxt<'tcx> {
+    type AdtDef = ty::AdtDef<'tcx>;
+    type SubstsRef = ty::SubstsRef<'tcx>;
+    type DefId = DefId;
+    type Ty = Ty<'tcx>;
+    type Const = ty::Const<'tcx>;
+    type Region = Region<'tcx>;
+    type TypeAndMut = TypeAndMut<'tcx>;
+    type Mutability = hir::Mutability;
+    type Movability = hir::Movability;
+    type PolyFnSig = PolyFnSig<'tcx>;
+    type ListBinderExistentialPredicate = &'tcx List<Binder<'tcx, ExistentialPredicate<'tcx>>>;
+    type BinderListTy = Binder<'tcx, &'tcx List<Ty<'tcx>>>;
+    type ListTy = &'tcx List<Ty<'tcx>>;
+    type ProjectionTy = ty::ProjectionTy<'tcx>;
+    type ParamTy = ParamTy;
+    type BoundTy = ty::BoundTy;
+    type PlaceholderType = ty::PlaceholderType;
+    type InferTy = InferTy;
+    type DelaySpanBugEmitted = DelaySpanBugEmitted;
+    type PredicateKind = ty::PredicateKind<'tcx>;
+    type AllocId = crate::mir::interpret::AllocId;
+
+    type EarlyBoundRegion = ty::EarlyBoundRegion;
+    type BoundRegion = ty::BoundRegion;
+    type FreeRegion = ty::FreeRegion;
+    type RegionVid = ty::RegionVid;
+    type PlaceholderRegion = ty::PlaceholderRegion;
 }
 
 /// A type that is not publicly constructable. This prevents people from making [`TyKind::Error`]s
@@ -109,7 +142,7 @@
     type_: InternedSet<'tcx, WithStableHash<TyS<'tcx>>>,
     substs: InternedSet<'tcx, InternalSubsts<'tcx>>,
     canonical_var_infos: InternedSet<'tcx, List<CanonicalVarInfo<'tcx>>>,
-    region: InternedSet<'tcx, RegionKind>,
+    region: InternedSet<'tcx, RegionKind<'tcx>>,
     poly_existential_predicates:
         InternedSet<'tcx, List<ty::Binder<'tcx, ExistentialPredicate<'tcx>>>>,
     predicate: InternedSet<'tcx, PredicateS<'tcx>>,
@@ -151,7 +184,9 @@
         &self,
         kind: TyKind<'tcx>,
         sess: &Session,
-        resolutions: &ty::ResolverOutputs,
+        definitions: &rustc_hir::definitions::Definitions,
+        cstore: &CrateStoreDyn,
+        source_span: &IndexVec<LocalDefId, Span>,
     ) -> Ty<'tcx> {
         Ty(Interned::new_unchecked(
             self.type_
@@ -168,8 +203,9 @@
                         let mut hasher = StableHasher::new();
                         let mut hcx = StableHashingContext::ignore_spans(
                             sess,
-                            &resolutions.definitions,
-                            &*resolutions.cstore,
+                            definitions,
+                            cstore,
+                            source_span,
                         );
                         kind.hash_stable(&mut hcx, &mut hasher);
                         hasher.finish()
@@ -535,6 +571,11 @@
     /// issue by fake reading `t`.
     pub closure_fake_reads: FxHashMap<DefId, Vec<(HirPlace<'tcx>, FakeReadCause, hir::HirId)>>,
 
+    /// Tracks the rvalue scoping rules which defines finer scoping for rvalue expressions
+    /// by applying extended parameter rules.
+    /// Details may be find in `rustc_typeck::check::rvalue_scopes`.
+    pub rvalue_scopes: RvalueScopes,
+
     /// Stores the type, expression, span and optional scope span of all types
     /// that are live across the yield of this generator (if a generator).
     pub generator_interior_types: ty::Binder<'tcx, Vec<GeneratorInteriorTypeCause<'tcx>>>,
@@ -572,6 +613,7 @@
             concrete_opaque_types: Default::default(),
             closure_min_captures: Default::default(),
             closure_fake_reads: Default::default(),
+            rvalue_scopes: Default::default(),
             generator_interior_types: ty::Binder::dummy(Default::default()),
             treat_byte_string_as_slice: Default::default(),
             closure_size_eval: Default::default(),
@@ -870,7 +912,7 @@
                             _ => false,
                         },
 
-                        GenericArgKind::Const(ct) => match ct.val() {
+                        GenericArgKind::Const(ct) => match ct.kind() {
                             ty::ConstKind::Bound(debruijn, b) => {
                                 // We only allow a `ty::INNERMOST` index in substitutions.
                                 assert_eq!(debruijn, ty::INNERMOST);
@@ -902,9 +944,11 @@
     fn new(
         interners: &CtxtInterners<'tcx>,
         sess: &Session,
-        resolutions: &ty::ResolverOutputs,
+        definitions: &rustc_hir::definitions::Definitions,
+        cstore: &CrateStoreDyn,
+        source_span: &IndexVec<LocalDefId, Span>,
     ) -> CommonTypes<'tcx> {
-        let mk = |ty| interners.intern_ty(ty, sess, resolutions);
+        let mk = |ty| interners.intern_ty(ty, sess, definitions, cstore, source_span);
 
         CommonTypes {
             unit: mk(Tuple(List::empty())),
@@ -959,7 +1003,7 @@
 
         CommonConsts {
             unit: mk_const(ty::ConstS {
-                val: ty::ConstKind::Value(ConstValue::Scalar(Scalar::ZST)),
+                kind: ty::ConstKind::Value(ty::ValTree::zst()),
                 ty: types.unit,
             }),
         }
@@ -1025,6 +1069,9 @@
     /// Common consts, pre-interned for your convenience.
     pub consts: CommonConsts<'tcx>,
 
+    definitions: rustc_hir::definitions::Definitions,
+    cstore: Box<CrateStoreDyn>,
+
     /// Output of the resolver.
     pub(crate) untracked_resolutions: ty::ResolverOutputs,
 
@@ -1186,7 +1233,9 @@
         s: &'tcx Session,
         lint_store: Lrc<dyn Any + sync::Send + sync::Sync>,
         arena: &'tcx WorkerLocal<Arena<'tcx>>,
-        resolutions: ty::ResolverOutputs,
+        definitions: rustc_hir::definitions::Definitions,
+        cstore: Box<CrateStoreDyn>,
+        untracked_resolutions: ty::ResolverOutputs,
         krate: &'tcx hir::Crate<'tcx>,
         dep_graph: DepGraph,
         on_disk_cache: Option<&'tcx dyn OnDiskCache<'tcx>>,
@@ -1199,7 +1248,14 @@
             s.fatal(&err);
         });
         let interners = CtxtInterners::new(arena);
-        let common_types = CommonTypes::new(&interners, s, &resolutions);
+        let common_types = CommonTypes::new(
+            &interners,
+            s,
+            &definitions,
+            &*cstore,
+            // This is only used to create a stable hashing context.
+            &untracked_resolutions.source_span,
+        );
         let common_lifetimes = CommonLifetimes::new(&interners);
         let common_consts = CommonConsts::new(&interners, &common_types);
 
@@ -1209,7 +1265,9 @@
             arena,
             interners,
             dep_graph,
-            untracked_resolutions: resolutions,
+            definitions,
+            cstore,
+            untracked_resolutions,
             prof: s.prof.clone(),
             types: common_types,
             lifetimes: common_lifetimes,
@@ -1230,7 +1288,7 @@
         }
     }
 
-    crate fn query_kind(self, k: DepKind) -> &'tcx DepKindStruct {
+    pub(crate) fn query_kind(self, k: DepKind) -> &'tcx DepKindStruct {
         &self.query_kinds[k as usize]
     }
 
@@ -1268,7 +1326,7 @@
     ) -> Const<'tcx> {
         let reported = self.sess.delay_span_bug(span, msg);
         self.mk_const(ty::ConstS {
-            val: ty::ConstKind::Error(DelaySpanBugEmitted { reported, _priv: () }),
+            kind: ty::ConstKind::Error(DelaySpanBugEmitted { reported, _priv: () }),
             ty,
         })
     }
@@ -1310,9 +1368,9 @@
     pub fn def_key(self, id: DefId) -> rustc_hir::definitions::DefKey {
         // Accessing the DefKey is ok, since it is part of DefPathHash.
         if let Some(id) = id.as_local() {
-            self.untracked_resolutions.definitions.def_key(id)
+            self.definitions.def_key(id)
         } else {
-            self.untracked_resolutions.cstore.def_key(id)
+            self.cstore.def_key(id)
         }
     }
 
@@ -1324,9 +1382,9 @@
     pub fn def_path(self, id: DefId) -> rustc_hir::definitions::DefPath {
         // Accessing the DefPath is ok, since it is part of DefPathHash.
         if let Some(id) = id.as_local() {
-            self.untracked_resolutions.definitions.def_path(id)
+            self.definitions.def_path(id)
         } else {
-            self.untracked_resolutions.cstore.def_path(id)
+            self.cstore.def_path(id)
         }
     }
 
@@ -1334,9 +1392,9 @@
     pub fn def_path_hash(self, def_id: DefId) -> rustc_hir::definitions::DefPathHash {
         // Accessing the DefPathHash is ok, it is incr. comp. stable.
         if let Some(def_id) = def_id.as_local() {
-            self.untracked_resolutions.definitions.def_path_hash(def_id)
+            self.definitions.def_path_hash(def_id)
         } else {
-            self.untracked_resolutions.cstore.def_path_hash(def_id)
+            self.cstore.def_path_hash(def_id)
         }
     }
 
@@ -1345,7 +1403,7 @@
         if crate_num == LOCAL_CRATE {
             self.sess.local_stable_crate_id()
         } else {
-            self.untracked_resolutions.cstore.stable_crate_id(crate_num)
+            self.cstore.stable_crate_id(crate_num)
         }
     }
 
@@ -1356,7 +1414,7 @@
         if stable_crate_id == self.sess.local_stable_crate_id() {
             LOCAL_CRATE
         } else {
-            self.untracked_resolutions.cstore.stable_crate_id_to_crate_num(stable_crate_id)
+            self.cstore.stable_crate_id_to_crate_num(stable_crate_id)
         }
     }
 
@@ -1371,16 +1429,12 @@
         // If this is a DefPathHash from the local crate, we can look up the
         // DefId in the tcx's `Definitions`.
         if stable_crate_id == self.sess.local_stable_crate_id() {
-            self.untracked_resolutions
-                .definitions
-                .local_def_path_hash_to_def_id(hash, err)
-                .to_def_id()
+            self.definitions.local_def_path_hash_to_def_id(hash, err).to_def_id()
         } else {
             // If this is a DefPathHash from an upstream crate, let the CrateStore map
             // it to a DefId.
-            let cstore = &self.untracked_resolutions.cstore;
-            let cnum = cstore.stable_crate_id_to_crate_num(stable_crate_id);
-            cstore.def_path_hash_to_def_id(cnum, hash)
+            let cnum = self.cstore.stable_crate_id_to_crate_num(stable_crate_id);
+            self.cstore.def_path_hash_to_def_id(cnum, hash)
         }
     }
 
@@ -1392,7 +1446,7 @@
         let (crate_name, stable_crate_id) = if def_id.is_local() {
             (self.crate_name, self.sess.local_stable_crate_id())
         } else {
-            let cstore = &self.untracked_resolutions.cstore;
+            let cstore = &self.cstore;
             (cstore.crate_name(def_id.krate), cstore.stable_crate_id(def_id.krate))
         };
 
@@ -1408,72 +1462,45 @@
 
     /// Note that this is *untracked* and should only be used within the query
     /// system if the result is otherwise tracked through queries
-    pub fn cstore_untracked(self) -> &'tcx ty::CrateStoreDyn {
-        &*self.untracked_resolutions.cstore
+    pub fn cstore_untracked(self) -> &'tcx CrateStoreDyn {
+        &*self.cstore
     }
 
     /// Note that this is *untracked* and should only be used within the query
     /// system if the result is otherwise tracked through queries
     pub fn definitions_untracked(self) -> &'tcx hir::definitions::Definitions {
-        &self.untracked_resolutions.definitions
+        &self.definitions
+    }
+
+    /// Note that this is *untracked* and should only be used within the query
+    /// system if the result is otherwise tracked through queries
+    #[inline]
+    pub fn source_span_untracked(self, def_id: LocalDefId) -> Span {
+        self.untracked_resolutions.source_span.get(def_id).copied().unwrap_or(DUMMY_SP)
     }
 
     #[inline(always)]
     pub fn create_stable_hashing_context(self) -> StableHashingContext<'tcx> {
-        let resolutions = &self.gcx.untracked_resolutions;
-        StableHashingContext::new(self.sess, &resolutions.definitions, &*resolutions.cstore)
+        StableHashingContext::new(
+            self.sess,
+            &self.definitions,
+            &*self.cstore,
+            &self.untracked_resolutions.source_span,
+        )
     }
 
     #[inline(always)]
     pub fn create_no_span_stable_hashing_context(self) -> StableHashingContext<'tcx> {
-        let resolutions = &self.gcx.untracked_resolutions;
         StableHashingContext::ignore_spans(
             self.sess,
-            &resolutions.definitions,
-            &*resolutions.cstore,
+            &self.definitions,
+            &*self.cstore,
+            &self.untracked_resolutions.source_span,
         )
     }
 
-    pub fn serialize_query_result_cache(self, encoder: &mut FileEncoder) -> FileEncodeResult {
-        self.on_disk_cache.as_ref().map_or(Ok(()), |c| c.serialize(self, encoder))
-    }
-
-    /// If `true`, we should use the MIR-based borrowck, but also
-    /// fall back on the AST borrowck if the MIR-based one errors.
-    pub fn migrate_borrowck(self) -> bool {
-        self.borrowck_mode().migrate()
-    }
-
-    /// What mode(s) of borrowck should we run? AST? MIR? both?
-    /// (Also considers the `#![feature(nll)]` setting.)
-    pub fn borrowck_mode(self) -> BorrowckMode {
-        // Here are the main constraints we need to deal with:
-        //
-        // 1. An opts.borrowck_mode of `BorrowckMode::Migrate` is
-        //    synonymous with no `-Z borrowck=...` flag at all.
-        //
-        // 2. We want to allow developers on the Nightly channel
-        //    to opt back into the "hard error" mode for NLL,
-        //    (which they can do via specifying `#![feature(nll)]`
-        //    explicitly in their crate).
-        //
-        // So, this precedence list is how pnkfelix chose to work with
-        // the above constraints:
-        //
-        // * `#![feature(nll)]` *always* means use NLL with hard
-        //   errors. (To simplify the code here, it now even overrides
-        //   a user's attempt to specify `-Z borrowck=compare`, which
-        //   we arguably do not need anymore and should remove.)
-        //
-        // * Otherwise, if no `-Z borrowck=...` then use migrate mode
-        //
-        // * Otherwise, use the behavior requested via `-Z borrowck=...`
-
-        if self.features().nll {
-            return BorrowckMode::Mir;
-        }
-
-        self.sess.opts.borrowck_mode
+    pub fn serialize_query_result_cache(self, encoder: FileEncoder) -> FileEncodeResult {
+        self.on_disk_cache.as_ref().map_or(Ok(0), |c| c.serialize(self, encoder))
     }
 
     /// If `true`, we should use lazy normalization for constants, otherwise
@@ -1556,7 +1583,7 @@
             Node::Item(&hir::Item { kind: ItemKind::Fn(..), .. }) => {}
             Node::TraitItem(&hir::TraitItem { kind: TraitItemKind::Fn(..), .. }) => {}
             Node::ImplItem(&hir::ImplItem { kind: ImplItemKind::Fn(..), .. }) => {}
-            Node::Expr(&hir::Expr { kind: ExprKind::Closure(..), .. }) => {}
+            Node::Expr(&hir::Expr { kind: ExprKind::Closure { .. }, .. }) => {}
             _ => return None,
         }
 
@@ -1669,7 +1696,7 @@
         impl<'a, 'tcx> Lift<'tcx> for $ty {
             type Lifted = $lifted;
             fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
-                if tcx.interners.$set.contains_pointer_to(&InternedInSet(self.0.0)) {
+                if tcx.interners.$set.contains_pointer_to(&InternedInSet(&*self.0.0)) {
                     // SAFETY: `self` is interned and therefore valid
                     // for the entire lifetime of the `TyCtxt`.
                     Some(unsafe { mem::transmute(self) })
@@ -2154,7 +2181,7 @@
 }
 
 direct_interners! {
-    region: mk_region(RegionKind): Region -> Region<'tcx>,
+    region: mk_region(RegionKind<'tcx>): Region -> Region<'tcx>,
     const_: mk_const(ConstS<'tcx>): Const -> Const<'tcx>,
     const_allocation: intern_const_alloc(Allocation): ConstAllocation -> ConstAllocation<'tcx>,
     layout: intern_layout(LayoutS<'tcx>): Layout -> Layout<'tcx>,
@@ -2203,6 +2230,20 @@
         })
     }
 
+    /// Given a `ty`, return whether it's an `impl Future<...>`.
+    pub fn ty_is_opaque_future(self, ty: Ty<'_>) -> bool {
+        let ty::Opaque(def_id, _) = ty.kind() else { return false };
+        let future_trait = self.lang_items().future_trait().unwrap();
+
+        self.explicit_item_bounds(def_id).iter().any(|(predicate, _)| {
+            let ty::PredicateKind::Trait(trait_predicate) = predicate.kind().skip_binder() else {
+                return false;
+            };
+            trait_predicate.trait_ref.def_id == future_trait
+                && trait_predicate.polarity == ImplPolarity::Positive
+        })
+    }
+
     /// Computes the def-ids of the transitive supertraits of `trait_def_id`. This (intentionally)
     /// does not compute the full elaborated super-predicates but just the set of def-ids. It is used
     /// to identify which traits may define a given associated type to help avoid cycle errors.
@@ -2253,14 +2294,21 @@
     /// Same a `self.mk_region(kind)`, but avoids accessing the interners if
     /// `*r == kind`.
     #[inline]
-    pub fn reuse_or_mk_region(self, r: Region<'tcx>, kind: RegionKind) -> Region<'tcx> {
+    pub fn reuse_or_mk_region(self, r: Region<'tcx>, kind: RegionKind<'tcx>) -> Region<'tcx> {
         if *r == kind { r } else { self.mk_region(kind) }
     }
 
     #[allow(rustc::usage_of_ty_tykind)]
     #[inline]
     pub fn mk_ty(self, st: TyKind<'tcx>) -> Ty<'tcx> {
-        self.interners.intern_ty(st, self.sess, &self.gcx.untracked_resolutions)
+        self.interners.intern_ty(
+            st,
+            self.sess,
+            &self.definitions,
+            &*self.cstore,
+            // This is only used to create a stable hashing context.
+            &self.untracked_resolutions.source_span,
+        )
     }
 
     #[inline]
@@ -2473,7 +2521,7 @@
 
     #[inline]
     pub fn mk_const_var(self, v: ConstVid<'tcx>, ty: Ty<'tcx>) -> Const<'tcx> {
-        self.mk_const(ty::ConstS { val: ty::ConstKind::Infer(InferConst::Var(v)), ty })
+        self.mk_const(ty::ConstS { kind: ty::ConstKind::Infer(InferConst::Var(v)), ty })
     }
 
     #[inline]
@@ -2493,7 +2541,7 @@
 
     #[inline]
     pub fn mk_const_infer(self, ic: InferConst<'tcx>, ty: Ty<'tcx>) -> ty::Const<'tcx> {
-        self.mk_const(ty::ConstS { val: ty::ConstKind::Infer(ic), ty })
+        self.mk_const(ty::ConstS { kind: ty::ConstKind::Infer(ic), ty })
     }
 
     #[inline]
@@ -2503,7 +2551,7 @@
 
     #[inline]
     pub fn mk_const_param(self, index: u32, name: Symbol, ty: Ty<'tcx>) -> Const<'tcx> {
-        self.mk_const(ty::ConstS { val: ty::ConstKind::Param(ParamConst { index, name }), ty })
+        self.mk_const(ty::ConstS { kind: ty::ConstKind::Param(ParamConst { index, name }), ty })
     }
 
     pub fn mk_param_from_def(self, param: &ty::GenericParamDef) -> GenericArg<'tcx> {
@@ -2771,6 +2819,13 @@
         self.named_region_map(id.owner).and_then(|map| map.get(&id.local_id).cloned())
     }
 
+    pub fn is_late_bound(self, id: HirId) -> bool {
+        self.is_late_bound_map(id.owner).map_or(false, |set| {
+            let def_id = self.hir().local_def_id(id);
+            set.contains(&def_id)
+        })
+    }
+
     pub fn late_bound_vars(self, id: HirId) -> &'tcx List<ty::BoundVariableKind> {
         self.mk_bound_variable_kinds(
             self.late_bound_vars_map(id.owner)
@@ -2782,16 +2837,12 @@
         )
     }
 
-    pub fn lifetime_scope(self, id: HirId) -> Option<&'tcx LifetimeScopeForPath> {
-        self.lifetime_scope_map(id.owner).as_ref().and_then(|map| map.get(&id.local_id))
-    }
-
     /// Whether the `def_id` counts as const fn in the current crate, considering all active
     /// feature gates
     pub fn is_const_fn(self, def_id: DefId) -> bool {
         if self.is_const_fn_raw(def_id) {
             match self.lookup_const_stability(def_id) {
-                Some(stability) if stability.level.is_unstable() => {
+                Some(stability) if stability.is_const_unstable() => {
                     // has a `rustc_const_unstable` attribute, check whether the user enabled the
                     // corresponding feature gate.
                     self.features()
@@ -2808,6 +2859,21 @@
             false
         }
     }
+
+    /// Whether the trait impl is marked const. This does not consider stability or feature gates.
+    pub fn is_const_trait_impl_raw(self, def_id: DefId) -> bool {
+        let Some(local_def_id) = def_id.as_local() else { return false };
+        let hir_id = self.local_def_id_to_hir_id(local_def_id);
+        let node = self.hir().get(hir_id);
+
+        matches!(
+            node,
+            hir::Node::Item(hir::Item {
+                kind: hir::ItemKind::Impl(hir::Impl { constness: hir::Constness::Const, .. }),
+                ..
+            })
+        )
+    }
 }
 
 impl<'tcx> TyCtxtAt<'tcx> {
@@ -2825,108 +2891,6 @@
     }
 }
 
-pub trait InternAs<T: ?Sized, R> {
-    type Output;
-    fn intern_with<F>(self, f: F) -> Self::Output
-    where
-        F: FnOnce(&T) -> R;
-}
-
-impl<I, T, R, E> InternAs<[T], R> for I
-where
-    E: InternIteratorElement<T, R>,
-    I: Iterator<Item = E>,
-{
-    type Output = E::Output;
-    fn intern_with<F>(self, f: F) -> Self::Output
-    where
-        F: FnOnce(&[T]) -> R,
-    {
-        E::intern_with(self, f)
-    }
-}
-
-pub trait InternIteratorElement<T, R>: Sized {
-    type Output;
-    fn intern_with<I: Iterator<Item = Self>, F: FnOnce(&[T]) -> R>(iter: I, f: F) -> Self::Output;
-}
-
-impl<T, R> InternIteratorElement<T, R> for T {
-    type Output = R;
-    fn intern_with<I: Iterator<Item = Self>, F: FnOnce(&[T]) -> R>(
-        mut iter: I,
-        f: F,
-    ) -> Self::Output {
-        // This code is hot enough that it's worth specializing for the most
-        // common length lists, to avoid the overhead of `SmallVec` creation.
-        // Lengths 0, 1, and 2 typically account for ~95% of cases. If
-        // `size_hint` is incorrect a panic will occur via an `unwrap` or an
-        // `assert`.
-        match iter.size_hint() {
-            (0, Some(0)) => {
-                assert!(iter.next().is_none());
-                f(&[])
-            }
-            (1, Some(1)) => {
-                let t0 = iter.next().unwrap();
-                assert!(iter.next().is_none());
-                f(&[t0])
-            }
-            (2, Some(2)) => {
-                let t0 = iter.next().unwrap();
-                let t1 = iter.next().unwrap();
-                assert!(iter.next().is_none());
-                f(&[t0, t1])
-            }
-            _ => f(&iter.collect::<SmallVec<[_; 8]>>()),
-        }
-    }
-}
-
-impl<'a, T, R> InternIteratorElement<T, R> for &'a T
-where
-    T: Clone + 'a,
-{
-    type Output = R;
-    fn intern_with<I: Iterator<Item = Self>, F: FnOnce(&[T]) -> R>(iter: I, f: F) -> Self::Output {
-        // This code isn't hot.
-        f(&iter.cloned().collect::<SmallVec<[_; 8]>>())
-    }
-}
-
-impl<T, R, E> InternIteratorElement<T, R> for Result<T, E> {
-    type Output = Result<R, E>;
-    fn intern_with<I: Iterator<Item = Self>, F: FnOnce(&[T]) -> R>(
-        mut iter: I,
-        f: F,
-    ) -> Self::Output {
-        // This code is hot enough that it's worth specializing for the most
-        // common length lists, to avoid the overhead of `SmallVec` creation.
-        // Lengths 0, 1, and 2 typically account for ~95% of cases. If
-        // `size_hint` is incorrect a panic will occur via an `unwrap` or an
-        // `assert`, unless a failure happens first, in which case the result
-        // will be an error anyway.
-        Ok(match iter.size_hint() {
-            (0, Some(0)) => {
-                assert!(iter.next().is_none());
-                f(&[])
-            }
-            (1, Some(1)) => {
-                let t0 = iter.next().unwrap()?;
-                assert!(iter.next().is_none());
-                f(&[t0])
-            }
-            (2, Some(2)) => {
-                let t0 = iter.next().unwrap()?;
-                let t1 = iter.next().unwrap()?;
-                assert!(iter.next().is_none());
-                f(&[t0, t1])
-            }
-            _ => f(&iter.collect::<Result<SmallVec<[_; 8]>, _>>()?),
-        })
-    }
-}
-
 // We are comparing types with different invariant lifetimes, so `ptr::eq`
 // won't work for us.
 fn ptr_eq<T, U>(t: *const T, u: *const U) -> bool {
@@ -2941,8 +2905,8 @@
         assert_eq!(id, LOCAL_CRATE);
         tcx.crate_name
     };
-    providers.maybe_unused_trait_import =
-        |tcx, id| tcx.resolutions(()).maybe_unused_trait_imports.contains(&id);
+    providers.maybe_unused_trait_imports =
+        |tcx, ()| &tcx.resolutions(()).maybe_unused_trait_imports;
     providers.maybe_unused_extern_crates =
         |tcx, ()| &tcx.resolutions(()).maybe_unused_extern_crates[..];
     providers.names_imported_by_glob_use = |tcx, id| {
diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs
index a671774..a84b3c9 100644
--- a/compiler/rustc_middle/src/ty/diagnostics.rs
+++ b/compiler/rustc_middle/src/ty/diagnostics.rs
@@ -1,10 +1,10 @@
 //! Diagnostics related methods for `Ty`.
 
-use crate::ty::subst::{GenericArg, GenericArgKind};
-use crate::ty::TyKind::*;
+use std::ops::ControlFlow;
+
 use crate::ty::{
-    ConstKind, DefIdTree, ExistentialPredicate, ExistentialProjection, ExistentialTraitRef,
-    InferTy, ProjectionTy, Term, Ty, TyCtxt, TypeAndMut,
+    fold::TypeFoldable, Const, ConstKind, DefIdTree, ExistentialPredicate, InferTy,
+    PolyTraitPredicate, Ty, TyCtxt, TypeSuperFoldable, TypeVisitor,
 };
 
 use rustc_data_structures::fx::FxHashMap;
@@ -13,6 +13,7 @@
 use rustc_hir::def_id::DefId;
 use rustc_hir::WherePredicate;
 use rustc_span::Span;
+use rustc_type_ir::sty::TyKind::*;
 
 impl<'tcx> IntoDiagnosticArg for Ty<'tcx> {
     fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
@@ -72,103 +73,55 @@
             _ => self.is_simple_ty(),
         }
     }
+}
 
-    /// Whether the type can be safely suggested during error recovery.
-    pub fn is_suggestable(self, tcx: TyCtxt<'tcx>) -> bool {
-        fn generic_arg_is_suggestible<'tcx>(arg: GenericArg<'tcx>, tcx: TyCtxt<'tcx>) -> bool {
-            match arg.unpack() {
-                GenericArgKind::Type(ty) => ty.is_suggestable(tcx),
-                GenericArgKind::Const(c) => const_is_suggestable(c.val()),
-                _ => true,
-            }
-        }
+pub trait IsSuggestable<'tcx> {
+    /// Whether this makes sense to suggest in a diagnostic.
+    ///
+    /// We filter out certain types and constants since they don't provide
+    /// meaningful rendered suggestions when pretty-printed. We leave some
+    /// nonsense, such as region vars, since those render as `'_` and are
+    /// usually okay to reinterpret as elided lifetimes.
+    fn is_suggestable(self, tcx: TyCtxt<'tcx>) -> bool;
+}
 
-        fn const_is_suggestable(kind: ConstKind<'_>) -> bool {
-            match kind {
-                ConstKind::Infer(..)
-                | ConstKind::Bound(..)
-                | ConstKind::Placeholder(..)
-                | ConstKind::Error(..) => false,
-                _ => true,
-            }
-        }
-
-        // FIXME(compiler-errors): Some types are still not good to suggest,
-        // specifically references with lifetimes within the function. Not
-        //sure we have enough information to resolve whether a region is
-        // temporary, so I'll leave this as a fixme.
-
-        match self.kind() {
-            FnDef(..)
-            | Closure(..)
-            | Infer(..)
-            | Generator(..)
-            | GeneratorWitness(..)
-            | Bound(_, _)
-            | Placeholder(_)
-            | Error(_) => false,
-            Opaque(did, substs) => {
-                let parent = tcx.parent(*did);
-                if let hir::def::DefKind::TyAlias | hir::def::DefKind::AssocTy = tcx.def_kind(parent)
-                    && let Opaque(parent_did, _) = tcx.type_of(parent).kind()
-                    && parent_did == did
-                {
-                    substs.iter().all(|a| generic_arg_is_suggestible(a, tcx))
-                } else {
-                    false
-                }
-            }
-            Dynamic(dty, _) => dty.iter().all(|pred| match pred.skip_binder() {
-                ExistentialPredicate::Trait(ExistentialTraitRef { substs, .. }) => {
-                    substs.iter().all(|a| generic_arg_is_suggestible(a, tcx))
-                }
-                ExistentialPredicate::Projection(ExistentialProjection {
-                    substs, term, ..
-                }) => {
-                    let term_is_suggestable = match term {
-                        Term::Ty(ty) => ty.is_suggestable(tcx),
-                        Term::Const(c) => const_is_suggestable(c.val()),
-                    };
-                    term_is_suggestable && substs.iter().all(|a| generic_arg_is_suggestible(a, tcx))
-                }
-                _ => true,
-            }),
-            Projection(ProjectionTy { substs: args, .. }) | Adt(_, args) => {
-                args.iter().all(|a| generic_arg_is_suggestible(a, tcx))
-            }
-            Tuple(args) => args.iter().all(|ty| ty.is_suggestable(tcx)),
-            Slice(ty) | RawPtr(TypeAndMut { ty, .. }) | Ref(_, ty, _) => ty.is_suggestable(tcx),
-            Array(ty, c) => ty.is_suggestable(tcx) && const_is_suggestable(c.val()),
-            _ => true,
-        }
+impl<'tcx, T> IsSuggestable<'tcx> for T
+where
+    T: TypeFoldable<'tcx>,
+{
+    fn is_suggestable(self, tcx: TyCtxt<'tcx>) -> bool {
+        self.visit_with(&mut IsSuggestableVisitor { tcx }).is_continue()
     }
 }
 
-pub fn suggest_arbitrary_trait_bound(
+pub fn suggest_arbitrary_trait_bound<'tcx>(
+    tcx: TyCtxt<'tcx>,
     generics: &hir::Generics<'_>,
     err: &mut Diagnostic,
-    param_name: &str,
-    constraint: &str,
+    trait_pred: PolyTraitPredicate<'tcx>,
 ) -> bool {
-    let param = generics.params.iter().find(|p| p.name.ident().as_str() == param_name);
-    match (param, param_name) {
-        (Some(_), "Self") => return false,
-        _ => {}
+    if !trait_pred.is_suggestable(tcx) {
+        return false;
     }
+
+    let param_name = trait_pred.skip_binder().self_ty().to_string();
+    let constraint = trait_pred.print_modifiers_and_trait_path().to_string();
+    let param = generics.params.iter().find(|p| p.name.ident().as_str() == param_name);
+
+    // Skip, there is a param named Self
+    if param.is_some() && param_name == "Self" {
+        return false;
+    }
+
     // Suggest a where clause bound for a non-type parameter.
-    let (action, prefix) = if generics.has_where_clause {
-        ("extending the", ", ")
-    } else {
-        ("introducing a", " where ")
-    };
     err.span_suggestion_verbose(
         generics.tail_span_for_predicate_suggestion(),
         &format!(
-            "consider {} `where` bound, but there might be an alternative better way to express \
+            "consider {} `where` clause, but there might be an alternative better way to express \
              this requirement",
-            action,
+            if generics.where_clause_span.is_empty() { "introducing a" } else { "extending the" },
         ),
-        format!("{}{}: {}", prefix, param_name, constraint),
+        format!("{} {}: {}", generics.add_where_or_trailing_comma(), param_name, constraint),
         Applicability::MaybeIncorrect,
     );
     true
@@ -272,7 +225,10 @@
             continue;
         }
 
-        let constraint = constraints.iter().map(|&(c, _)| c).collect::<Vec<_>>().join(" + ");
+        let mut constraint = constraints.iter().map(|&(c, _)| c).collect::<Vec<_>>();
+        constraint.sort();
+        constraint.dedup();
+        let constraint = constraint.join(" + ");
         let mut suggest_restrict = |span, bound_list_non_empty| {
             suggestions.push((
                 span,
@@ -318,7 +274,7 @@
             continue;
         }
 
-        if generics.has_where_clause {
+        if generics.has_where_clause_predicates {
             // This part is a bit tricky, because using the `where` clause user can
             // provide zero, one or many bounds for the same type parameter, so we
             // have following cases to consider:
@@ -460,3 +416,78 @@
         }
     }
 }
+
+pub struct IsSuggestableVisitor<'tcx> {
+    tcx: TyCtxt<'tcx>,
+}
+
+impl<'tcx> TypeVisitor<'tcx> for IsSuggestableVisitor<'tcx> {
+    type BreakTy = ();
+
+    fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
+        match t.kind() {
+            FnDef(..)
+            | Closure(..)
+            | Infer(..)
+            | Generator(..)
+            | GeneratorWitness(..)
+            | Bound(_, _)
+            | Placeholder(_)
+            | Error(_) => {
+                return ControlFlow::Break(());
+            }
+
+            Opaque(did, _) => {
+                let parent = self.tcx.parent(*did);
+                if let hir::def::DefKind::TyAlias | hir::def::DefKind::AssocTy = self.tcx.def_kind(parent)
+                    && let Opaque(parent_did, _) = self.tcx.type_of(parent).kind()
+                    && parent_did == did
+                {
+                    // Okay
+                } else {
+                    return ControlFlow::Break(());
+                }
+            }
+
+            Dynamic(dty, _) => {
+                for pred in *dty {
+                    match pred.skip_binder() {
+                        ExistentialPredicate::Trait(_) | ExistentialPredicate::Projection(_) => {
+                            // Okay
+                        }
+                        _ => return ControlFlow::Break(()),
+                    }
+                }
+            }
+
+            Param(param) => {
+                // FIXME: It would be nice to make this not use string manipulation,
+                // but it's pretty hard to do this, since `ty::ParamTy` is missing
+                // sufficient info to determine if it is synthetic, and we don't
+                // always have a convenient way of getting `ty::Generics` at the call
+                // sites we invoke `IsSuggestable::is_suggestable`.
+                if param.name.as_str().starts_with("impl ") {
+                    return ControlFlow::Break(());
+                }
+            }
+
+            _ => {}
+        }
+
+        t.super_visit_with(self)
+    }
+
+    fn visit_const(&mut self, c: Const<'tcx>) -> ControlFlow<Self::BreakTy> {
+        match c.kind() {
+            ConstKind::Infer(..)
+            | ConstKind::Bound(..)
+            | ConstKind::Placeholder(..)
+            | ConstKind::Error(..) => {
+                return ControlFlow::Break(());
+            }
+            _ => {}
+        }
+
+        c.super_visit_with(self)
+    }
+}
diff --git a/compiler/rustc_middle/src/ty/erase_regions.rs b/compiler/rustc_middle/src/ty/erase_regions.rs
index ef4f77c..6d7e60e 100644
--- a/compiler/rustc_middle/src/ty/erase_regions.rs
+++ b/compiler/rustc_middle/src/ty/erase_regions.rs
@@ -1,5 +1,5 @@
 use crate::mir;
-use crate::ty::fold::{TypeFoldable, TypeFolder};
+use crate::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
 use crate::ty::{self, Ty, TyCtxt, TypeFlags};
 
 pub(super) fn provide(providers: &mut ty::query::Providers) {
diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs
index a0fe632..812dd2a 100644
--- a/compiler/rustc_middle/src/ty/error.rs
+++ b/compiler/rustc_middle/src/ty/error.rs
@@ -135,11 +135,10 @@
             ArgCount => write!(f, "incorrect number of function parameters"),
             FieldMisMatch(adt, field) => write!(f, "field type mismatch: {}.{}", adt, field),
             RegionsDoesNotOutlive(..) => write!(f, "lifetime mismatch"),
-            RegionsInsufficientlyPolymorphic(br, _) => write!(
-                f,
-                "expected bound lifetime parameter{}, found concrete lifetime",
-                br_string(br)
-            ),
+            // Actually naming the region here is a bit confusing because context is lacking
+            RegionsInsufficientlyPolymorphic(..) => {
+                write!(f, "one type is more general than the other")
+            }
             RegionsOverlyPolymorphic(br, _) => write!(
                 f,
                 "expected concrete lifetime, found bound lifetime parameter{}",
@@ -255,7 +254,7 @@
                 }
 
                 let n = tcx.lift(n).unwrap();
-                if let ty::ConstKind::Value(v) = n.val() {
+                if let ty::ConstKind::Value(v) = n.kind() {
                     if let Some(n) = v.try_to_machine_usize(tcx) {
                         return format!("array of {} element{}", n, pluralize!(n)).into();
                     }
diff --git a/compiler/rustc_middle/src/ty/fast_reject.rs b/compiler/rustc_middle/src/ty/fast_reject.rs
index 9c018dc..a8145e6 100644
--- a/compiler/rustc_middle/src/ty/fast_reject.rs
+++ b/compiler/rustc_middle/src/ty/fast_reject.rs
@@ -1,11 +1,10 @@
 use crate::mir::Mutability;
-use crate::ty::{self, Ty, TyCtxt};
-use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use crate::ty::subst::GenericArgKind;
+use crate::ty::{self, Ty, TyCtxt, TypeFoldable};
 use rustc_hir::def_id::DefId;
-use rustc_query_system::ich::StableHashingContext;
 use std::fmt::Debug;
 use std::hash::Hash;
-use std::mem;
+use std::iter;
 
 use self::SimplifiedTypeGen::*;
 
@@ -17,7 +16,7 @@
 /// because we sometimes need to use SimplifiedTypeGen values as stable sorting
 /// keys (in which case we use a DefPathHash as id-type) but in the general case
 /// the non-stable but fast to construct DefId-version is the better choice.
-#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)]
 pub enum SimplifiedTypeGen<D>
 where
     D: Copy + Debug + Eq,
@@ -45,34 +44,53 @@
     GeneratorWitnessSimplifiedType(usize),
     OpaqueSimplifiedType(D),
     FunctionSimplifiedType(usize),
-    ParameterSimplifiedType,
+    PlaceholderSimplifiedType,
 }
 
+/// Generic parameters are pretty much just bound variables, e.g.
+/// the type of `fn foo<'a, T>(x: &'a T) -> u32 { ... }` can be thought of as
+/// `for<'a, T> fn(&'a T) -> u32`.
+///
+/// Typecheck of `foo` has to succeed for all possible generic arguments, so
+/// during typeck, we have to treat its generic parameters as if they
+/// were placeholders.
+///
+/// But when calling `foo` we only have to provide a specific generic argument.
+/// In that case the generic parameters are instantiated with inference variables.
+/// As we use `simplify_type` before that instantiation happens, we just treat
+/// generic parameters as if they were inference variables in that case.
 #[derive(PartialEq, Eq, Debug, Clone, Copy)]
 pub enum TreatParams {
-    /// Treat parameters as bound types in the given environment.
+    /// Treat parameters as placeholders in the given environment.
     ///
-    /// For this to be correct the input has to be fully normalized
-    /// in its param env as it may otherwise cause us to ignore
-    /// potentially applying impls.
-    AsBoundTypes,
-    AsPlaceholders,
+    /// Note that this also causes us to treat projections as if they were
+    /// placeholders. This is only correct if the given projection cannot
+    /// be normalized in the current context. Even if normalization fails,
+    /// it may still succeed later if the projection contains any inference
+    /// variables.
+    AsPlaceholder,
+    AsInfer,
 }
 
 /// Tries to simplify a type by only returning the outermost injective¹ layer, if one exists.
 ///
+/// **This function should only be used if you need to store or retrieve the type from some
+/// hashmap. If you want to quickly decide whether two types may unify, use the [DeepRejectCtxt]
+/// instead.**
+///
 /// The idea is to get something simple that we can use to quickly decide if two types could unify,
-/// for example during method lookup.
+/// for example during method lookup. If this function returns `Some(x)` it can only unify with
+/// types for which this method returns either `Some(x)` as well or `None`.
 ///
 /// A special case here are parameters and projections, which are only injective
-/// if they are treated as bound types.
+/// if they are treated as placeholders.
 ///
 /// For example when storing impls based on their simplified self type, we treat
-/// generic parameters as placeholders. We must not simplify them here,
+/// generic parameters as if they were inference variables. We must not simplify them here,
 /// as they can unify with any other type.
 ///
-/// With projections we have to be even more careful, as even when treating them as bound types
-/// this is still only correct if they are fully normalized.
+/// With projections we have to be even more careful, as treating them as placeholders
+/// is only correct if they are fully normalized.
 ///
 /// ¹ meaning that if the outermost layers are different, then the whole types are also different.
 pub fn simplify_type<'tcx>(
@@ -104,20 +122,25 @@
         ty::Never => Some(NeverSimplifiedType),
         ty::Tuple(tys) => Some(TupleSimplifiedType(tys.len())),
         ty::FnPtr(f) => Some(FunctionSimplifiedType(f.skip_binder().inputs().len())),
-        ty::Param(_) | ty::Projection(_) => match treat_params {
-            // When treated as bound types, projections don't unify with
-            // anything as long as they are fully normalized.
+        ty::Placeholder(..) => Some(PlaceholderSimplifiedType),
+        ty::Param(_) => match treat_params {
+            TreatParams::AsPlaceholder => Some(PlaceholderSimplifiedType),
+            TreatParams::AsInfer => None,
+        },
+        ty::Projection(_) => match treat_params {
+            // When treating `ty::Param` as a placeholder, projections also
+            // don't unify with anything else as long as they are fully normalized.
             //
             // We will have to be careful with lazy normalization here.
-            TreatParams::AsBoundTypes => {
-                debug!("treating `{}` as a bound type", ty);
-                Some(ParameterSimplifiedType)
+            TreatParams::AsPlaceholder if !ty.has_infer_types_or_consts() => {
+                debug!("treating `{}` as a placeholder", ty);
+                Some(PlaceholderSimplifiedType)
             }
-            TreatParams::AsPlaceholders => None,
+            TreatParams::AsPlaceholder | TreatParams::AsInfer => None,
         },
         ty::Opaque(def_id, _) => Some(OpaqueSimplifiedType(def_id)),
         ty::Foreign(def_id) => Some(ForeignSimplifiedType(def_id)),
-        ty::Placeholder(..) | ty::Bound(..) | ty::Infer(_) | ty::Error(_) => None,
+        ty::Bound(..) | ty::Infer(_) | ty::Error(_) => None,
     }
 }
 
@@ -161,41 +184,222 @@
             GeneratorWitnessSimplifiedType(n) => GeneratorWitnessSimplifiedType(n),
             OpaqueSimplifiedType(d) => OpaqueSimplifiedType(map(d)),
             FunctionSimplifiedType(n) => FunctionSimplifiedType(n),
-            ParameterSimplifiedType => ParameterSimplifiedType,
+            PlaceholderSimplifiedType => PlaceholderSimplifiedType,
         }
     }
 }
 
-impl<'a, D> HashStable<StableHashingContext<'a>> for SimplifiedTypeGen<D>
-where
-    D: Copy + Debug + Eq + HashStable<StableHashingContext<'a>>,
-{
-    fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
-        mem::discriminant(self).hash_stable(hcx, hasher);
-        match *self {
-            BoolSimplifiedType
-            | CharSimplifiedType
-            | StrSimplifiedType
-            | ArraySimplifiedType
-            | SliceSimplifiedType
-            | NeverSimplifiedType
-            | ParameterSimplifiedType
-            | MarkerTraitObjectSimplifiedType => {
-                // nothing to do
+/// Given generic arguments from an obligation and an impl,
+/// could these two be unified after replacing parameters in the
+/// the impl with inference variables.
+///
+/// For obligations, parameters won't be replaced by inference
+/// variables and only unify with themselves. We treat them
+/// the same way we treat placeholders.
+///
+/// We also use this function during coherence. For coherence the
+/// impls only have to overlap for some value, so we treat parameters
+/// on both sides like inference variables. This behavior is toggled
+/// using the `treat_obligation_params` field.
+#[derive(Debug, Clone, Copy)]
+pub struct DeepRejectCtxt {
+    pub treat_obligation_params: TreatParams,
+}
+
+impl DeepRejectCtxt {
+    pub fn generic_args_may_unify<'tcx>(
+        self,
+        obligation_arg: ty::GenericArg<'tcx>,
+        impl_arg: ty::GenericArg<'tcx>,
+    ) -> bool {
+        match (obligation_arg.unpack(), impl_arg.unpack()) {
+            // We don't fast reject based on regions for now.
+            (GenericArgKind::Lifetime(_), GenericArgKind::Lifetime(_)) => true,
+            (GenericArgKind::Type(obl), GenericArgKind::Type(imp)) => {
+                self.types_may_unify(obl, imp)
             }
-            RefSimplifiedType(m) | PtrSimplifiedType(m) => m.hash_stable(hcx, hasher),
-            IntSimplifiedType(t) => t.hash_stable(hcx, hasher),
-            UintSimplifiedType(t) => t.hash_stable(hcx, hasher),
-            FloatSimplifiedType(t) => t.hash_stable(hcx, hasher),
-            AdtSimplifiedType(d) => d.hash_stable(hcx, hasher),
-            TupleSimplifiedType(n) => n.hash_stable(hcx, hasher),
-            TraitSimplifiedType(d) => d.hash_stable(hcx, hasher),
-            ClosureSimplifiedType(d) => d.hash_stable(hcx, hasher),
-            GeneratorSimplifiedType(d) => d.hash_stable(hcx, hasher),
-            GeneratorWitnessSimplifiedType(n) => n.hash_stable(hcx, hasher),
-            OpaqueSimplifiedType(d) => d.hash_stable(hcx, hasher),
-            FunctionSimplifiedType(n) => n.hash_stable(hcx, hasher),
-            ForeignSimplifiedType(d) => d.hash_stable(hcx, hasher),
+            (GenericArgKind::Const(obl), GenericArgKind::Const(imp)) => {
+                self.consts_may_unify(obl, imp)
+            }
+            _ => bug!("kind mismatch: {obligation_arg} {impl_arg}"),
+        }
+    }
+
+    pub fn types_may_unify<'tcx>(self, obligation_ty: Ty<'tcx>, impl_ty: Ty<'tcx>) -> bool {
+        match impl_ty.kind() {
+            // Start by checking whether the type in the impl may unify with
+            // pretty much everything. Just return `true` in that case.
+            ty::Param(_) | ty::Projection(_) | ty::Error(_) => return true,
+            // These types only unify with inference variables or their own
+            // variant.
+            ty::Bool
+            | ty::Char
+            | ty::Int(_)
+            | ty::Uint(_)
+            | ty::Float(_)
+            | ty::Adt(..)
+            | ty::Str
+            | ty::Array(..)
+            | ty::Slice(..)
+            | ty::RawPtr(..)
+            | ty::Dynamic(..)
+            | ty::Ref(..)
+            | ty::Never
+            | ty::Tuple(..)
+            | ty::FnPtr(..)
+            | ty::Foreign(..)
+            | ty::Opaque(..) => {}
+            ty::FnDef(..)
+            | ty::Closure(..)
+            | ty::Generator(..)
+            | ty::GeneratorWitness(..)
+            | ty::Placeholder(..)
+            | ty::Bound(..)
+            | ty::Infer(_) => bug!("unexpected impl_ty: {impl_ty}"),
+        }
+
+        let k = impl_ty.kind();
+        match *obligation_ty.kind() {
+            // Purely rigid types, use structural equivalence.
+            ty::Bool
+            | ty::Char
+            | ty::Int(_)
+            | ty::Uint(_)
+            | ty::Float(_)
+            | ty::Str
+            | ty::Never
+            | ty::Foreign(_) => obligation_ty == impl_ty,
+            ty::Ref(_, obl_ty, obl_mutbl) => match k {
+                &ty::Ref(_, impl_ty, impl_mutbl) => {
+                    obl_mutbl == impl_mutbl && self.types_may_unify(obl_ty, impl_ty)
+                }
+                _ => false,
+            },
+            ty::Adt(obl_def, obl_substs) => match k {
+                &ty::Adt(impl_def, impl_substs) => {
+                    obl_def == impl_def
+                        && iter::zip(obl_substs, impl_substs)
+                            .all(|(obl, imp)| self.generic_args_may_unify(obl, imp))
+                }
+                _ => false,
+            },
+            ty::Slice(obl_ty) => {
+                matches!(k, &ty::Slice(impl_ty) if self.types_may_unify(obl_ty, impl_ty))
+            }
+            ty::Array(obl_ty, obl_len) => match k {
+                &ty::Array(impl_ty, impl_len) => {
+                    self.types_may_unify(obl_ty, impl_ty)
+                        && self.consts_may_unify(obl_len, impl_len)
+                }
+                _ => false,
+            },
+            ty::Tuple(obl) => match k {
+                &ty::Tuple(imp) => {
+                    obl.len() == imp.len()
+                        && iter::zip(obl, imp).all(|(obl, imp)| self.types_may_unify(obl, imp))
+                }
+                _ => false,
+            },
+            ty::RawPtr(obl) => match k {
+                ty::RawPtr(imp) => obl.mutbl == imp.mutbl && self.types_may_unify(obl.ty, imp.ty),
+                _ => false,
+            },
+            ty::Dynamic(obl_preds, ..) => {
+                // Ideally we would walk the existential predicates here or at least
+                // compare their length. But considering that the relevant `Relate` impl
+                // actually sorts and deduplicates these, that doesn't work.
+                matches!(k, ty::Dynamic(impl_preds, ..) if
+                    obl_preds.principal_def_id() == impl_preds.principal_def_id()
+                )
+            }
+            ty::FnPtr(obl_sig) => match k {
+                ty::FnPtr(impl_sig) => {
+                    let ty::FnSig { inputs_and_output, c_variadic, unsafety, abi } =
+                        obl_sig.skip_binder();
+                    let impl_sig = impl_sig.skip_binder();
+
+                    abi == impl_sig.abi
+                        && c_variadic == impl_sig.c_variadic
+                        && unsafety == impl_sig.unsafety
+                        && inputs_and_output.len() == impl_sig.inputs_and_output.len()
+                        && iter::zip(inputs_and_output, impl_sig.inputs_and_output)
+                            .all(|(obl, imp)| self.types_may_unify(obl, imp))
+                }
+                _ => false,
+            },
+
+            // Opaque types in impls should be forbidden, but that doesn't
+            // stop compilation. So this match arm should never return true
+            // if compilation succeeds.
+            ty::Opaque(..) => matches!(k, ty::Opaque(..)),
+
+            // Impls cannot contain these types as these cannot be named directly.
+            ty::FnDef(..) | ty::Closure(..) | ty::Generator(..) => false,
+
+            ty::Placeholder(..) => false,
+
+            // Depending on the value of `treat_obligation_params`, we either
+            // treat generic parameters like placeholders or like inference variables.
+            ty::Param(_) => match self.treat_obligation_params {
+                TreatParams::AsPlaceholder => false,
+                TreatParams::AsInfer => true,
+            },
+
+            ty::Infer(_) => true,
+
+            // As we're walking the whole type, it may encounter projections
+            // inside of binders and what not, so we're just going to assume that
+            // projections can unify with other stuff.
+            //
+            // Looking forward to lazy normalization this is the safer strategy anyways.
+            ty::Projection(_) => true,
+
+            ty::Error(_) => true,
+
+            ty::GeneratorWitness(..) | ty::Bound(..) => {
+                bug!("unexpected obligation type: {:?}", obligation_ty)
+            }
+        }
+    }
+
+    pub fn consts_may_unify(self, obligation_ct: ty::Const<'_>, impl_ct: ty::Const<'_>) -> bool {
+        match impl_ct.kind() {
+            ty::ConstKind::Param(_) | ty::ConstKind::Unevaluated(_) | ty::ConstKind::Error(_) => {
+                return true;
+            }
+            ty::ConstKind::Value(_) => {}
+            ty::ConstKind::Infer(_) | ty::ConstKind::Bound(..) | ty::ConstKind::Placeholder(_) => {
+                bug!("unexpected impl arg: {:?}", impl_ct)
+            }
+        }
+
+        let k = impl_ct.kind();
+        match obligation_ct.kind() {
+            ty::ConstKind::Param(_) => match self.treat_obligation_params {
+                TreatParams::AsPlaceholder => false,
+                TreatParams::AsInfer => true,
+            },
+
+            // As we don't necessarily eagerly evaluate constants,
+            // they might unify with any value.
+            ty::ConstKind::Unevaluated(_) | ty::ConstKind::Error(_) => true,
+            ty::ConstKind::Value(obl) => match k {
+                ty::ConstKind::Value(imp) => {
+                    // FIXME(valtrees): Once we have valtrees, we can just
+                    // compare them directly here.
+                    match (obl.try_to_scalar_int(), imp.try_to_scalar_int()) {
+                        (Some(obl), Some(imp)) => obl == imp,
+                        _ => true,
+                    }
+                }
+                _ => true,
+            },
+
+            ty::ConstKind::Infer(_) => true,
+
+            ty::ConstKind::Bound(..) | ty::ConstKind::Placeholder(_) => {
+                bug!("unexpected obl const: {:?}", obligation_ct)
+            }
         }
     }
 }
diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs
index 7a3d615..ea6bb8a 100644
--- a/compiler/rustc_middle/src/ty/flags.rs
+++ b/compiler/rustc_middle/src/ty/flags.rs
@@ -288,7 +288,7 @@
 
     fn add_const(&mut self, c: ty::Const<'_>) {
         self.add_ty(c.ty());
-        match c.val() {
+        match c.kind() {
             ty::ConstKind::Unevaluated(unevaluated) => self.add_unevaluated_const(unevaluated),
             ty::ConstKind::Infer(infer) => {
                 self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs
index a2a450d..31b8fa1 100644
--- a/compiler/rustc_middle/src/ty/fold.rs
+++ b/compiler/rustc_middle/src/ty/fold.rs
@@ -15,16 +15,20 @@
 //! the ones containing the most important type-related information, such as
 //! `Ty`, `Predicate`, `Region`, and `Const`.
 //!
-//! There are two traits involved in each traversal type.
-//! - The first trait is `TypeFoldable`, which is implemented once for many
-//!   types. This includes both (a) types of interest, and (b) all other
-//!   relevant types, including generic containers like `Vec` and `Option`. It
-//!   defines a "skeleton" of how they should be traversed, for both folding
-//!   and visiting.
-//! - The second trait is `TypeFolder`/`FallibleTypeFolder` (for
-//!   infallible/fallible folding traversals) or `TypeVisitor` (for visiting
-//!   traversals). One of these is implemented for each folder/visitor. This
-//!   defines how types of interest are handled.
+//! There are three traits involved in each traversal type.
+//! - `TypeFoldable`. This is implemented once for many types. This includes
+//!   both:
+//!   - Types of interest, for which the the methods delegate to the
+//!     folder/visitor.
+//!   - All other types, including generic containers like `Vec` and `Option`.
+//!     It defines a "skeleton" of how they should be traversed, for both
+//!     folding and visiting.
+//! - `TypeSuperFoldable`. This is implemented only for each type of interest,
+//!   and defines the traversal "skeleton" for these types.
+//! - `TypeFolder`/`FallibleTypeFolder` (for infallible/fallible folding
+//!   traversals) or `TypeVisitor` (for visiting traversals). One of these is
+//!   implemented for each folder/visitor. This defines how types of interest
+//!   are folded/visited.
 //!
 //! This means each traversal is a mixture of (a) generic traversal operations,
 //! and (b) custom fold/visit operations that are specific to the
@@ -32,22 +36,23 @@
 //! - The `TypeFoldable` impls handle most of the traversal, and call into
 //!   `TypeFolder`/`FallibleTypeFolder`/`TypeVisitor` when they encounter a
 //!   type of interest.
-//! - A `TypeFolder`/`FallibleTypeFolder`/`TypeVisitor` may also call back into
-//!   a `TypeFoldable` impl, because (a) the types of interest are recursive
-//!   and can contain other types of interest, and (b) each folder/visitor
-//!   might provide custom handling only for some types of interest, or only
-//!   for some variants of each type of interest, and then use default
-//!   traversal for the remaining cases.
+//! - A `TypeFolder`/`FallibleTypeFolder`/`TypeVisitor` may call into another
+//!   `TypeFoldable` impl, because some of the types of interest are recursive
+//!   and can contain other types of interest.
+//! - A `TypeFolder`/`FallibleTypeFolder`/`TypeVisitor` may also call into
+//!   a `TypeSuperFoldable` impl, because each folder/visitor might provide
+//!   custom handling only for some types of interest, or only for some
+//!   variants of each type of interest, and then use default traversal for the
+//!   remaining cases.
 //!
 //! For example, if you have `struct S(Ty, U)` where `S: TypeFoldable` and `U:
-//! TypeFoldable`, and an instance `S(ty, u)`, it would be visited like so:
+//! TypeFoldable`, and an instance `s = S(ty, u)`, it would be visited like so:
 //! ```text
 //! s.visit_with(visitor) calls
-//! - s.super_visit_with(visitor) calls
-//!   - ty.visit_with(visitor) calls
-//!     - visitor.visit_ty(ty) may call
-//!       - ty.super_visit_with(visitor)
-//!   - u.visit_with(visitor)
+//! - ty.visit_with(visitor) calls
+//!   - visitor.visit_ty(ty) may call
+//!     - ty.super_visit_with(visitor)
+//! - u.visit_with(visitor)
 //! ```
 use crate::mir;
 use crate::ty::{self, flags::FlagComputation, Binder, Ty, TyCtxt, TypeFlags};
@@ -66,18 +71,17 @@
 /// To implement this conveniently, use the derive macro located in
 /// `rustc_macros`.
 pub trait TypeFoldable<'tcx>: fmt::Debug + Clone {
-    /// The main entry point for folding. To fold a value `t` with a folder `f`
+    /// The entry point for folding. To fold a value `t` with a folder `f`
     /// call: `t.try_fold_with(f)`.
     ///
-    /// For types of interest (such as `Ty`), this default is overridden with a
-    /// method that calls a folder method specifically for that type (such as
+    /// For most types, this just traverses the value, calling `try_fold_with`
+    /// on each field/element.
+    ///
+    /// For types of interest (such as `Ty`), the implementation of method
+    /// calls a folder method specifically for that type (such as
     /// `F::try_fold_ty`). This is where control transfers from `TypeFoldable`
     /// to `TypeFolder`.
-    ///
-    /// For other types, this default is used.
-    fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
-        self.try_super_fold_with(folder)
-    }
+    fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error>;
 
     /// A convenient alternative to `try_fold_with` for use with infallible
     /// folders. Do not override this method, to ensure coherence with
@@ -86,40 +90,17 @@
         self.try_fold_with(folder).into_ok()
     }
 
-    /// Traverses the type in question, typically by calling `try_fold_with` on
-    /// each field/element. This is true even for types of interest such as
-    /// `Ty`. This should only be called within `TypeFolder` methods, when
-    /// non-custom traversals are desired for types of interest.
-    fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
-        self,
-        folder: &mut F,
-    ) -> Result<Self, F::Error>;
-
-    /// A convenient alternative to `try_super_fold_with` for use with
-    /// infallible folders. Do not override this method, to ensure coherence
-    /// with `try_super_fold_with`.
-    fn super_fold_with<F: TypeFolder<'tcx, Error = !>>(self, folder: &mut F) -> Self {
-        self.try_super_fold_with(folder).into_ok()
-    }
-
     /// The entry point for visiting. To visit a value `t` with a visitor `v`
     /// call: `t.visit_with(v)`.
     ///
-    /// For types of interest (such as `Ty`), this default is overridden with a
-    /// method that calls a visitor method specifically for that type (such as
+    /// For most types, this just traverses the value, calling `visit_with` on
+    /// each field/element.
+    ///
+    /// For types of interest (such as `Ty`), the implementation of this method
+    /// that calls a visitor method specifically for that type (such as
     /// `V::visit_ty`). This is where control transfers from `TypeFoldable` to
     /// `TypeVisitor`.
-    ///
-    /// For other types, this default is used.
-    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
-        self.super_visit_with(visitor)
-    }
-
-    /// Traverses the type in question, typically by calling `visit_with` on
-    /// each field/element. This is true even for types of interest such as
-    /// `Ty`. This should only be called within `TypeVisitor` methods, when
-    /// non-custom traversals are desired for types of interest.
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy>;
+    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy>;
 
     /// Returns `true` if `self` has any late-bound regions that are either
     /// bound by `binder` or bound by some binder outside of `binder`.
@@ -219,9 +200,40 @@
     }
 }
 
+// This trait is implemented for types of interest.
+pub trait TypeSuperFoldable<'tcx>: TypeFoldable<'tcx> {
+    /// Provides a default fold for a type of interest. This should only be
+    /// called within `TypeFolder` methods, when a non-custom traversal is
+    /// desired for the value of the type of interest passed to that method.
+    /// For example, in `MyFolder::try_fold_ty(ty)`, it is valid to call
+    /// `ty.try_super_fold_with(self)`, but any other folding should be done
+    /// with `xyz.try_fold_with(self)`.
+    fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+        self,
+        folder: &mut F,
+    ) -> Result<Self, F::Error>;
+
+    /// A convenient alternative to `try_super_fold_with` for use with
+    /// infallible folders. Do not override this method, to ensure coherence
+    /// with `try_super_fold_with`.
+    fn super_fold_with<F: TypeFolder<'tcx, Error = !>>(self, folder: &mut F) -> Self {
+        self.try_super_fold_with(folder).into_ok()
+    }
+
+    /// Provides a default visit for a type of interest. This should only be
+    /// called within `TypeVisitor` methods, when a non-custom traversal is
+    /// desired for the value of the type of interest passed to that method.
+    /// For example, in `MyVisitor::visit_ty(ty)`, it is valid to call
+    /// `ty.super_visit_with(self)`, but any other visiting should be done
+    /// with `xyz.visit_with(self)`.
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy>;
+}
+
 /// This trait is implemented for every folding traversal. There is a fold
 /// method defined for every type of interest. Each such method has a default
-/// that does an "identity" fold.
+/// that does an "identity" fold. Implementations of these methods often fall
+/// back to a `super_fold_with` method if the primary argument doesn't
+/// satisfy a particular condition.
 ///
 /// If this folder is fallible (and therefore its [`Error`][`TypeFolder::Error`]
 /// associated type is something other than the default `!`) then
@@ -263,6 +275,13 @@
         c.super_fold_with(self)
     }
 
+    fn fold_unevaluated(&mut self, uv: ty::Unevaluated<'tcx>) -> ty::Unevaluated<'tcx>
+    where
+        Self: TypeFolder<'tcx, Error = !>,
+    {
+        uv.super_fold_with(self)
+    }
+
     fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx>
     where
         Self: TypeFolder<'tcx, Error = !>,
@@ -305,6 +324,13 @@
         c.try_super_fold_with(self)
     }
 
+    fn try_fold_unevaluated(
+        &mut self,
+        c: ty::Unevaluated<'tcx>,
+    ) -> Result<ty::Unevaluated<'tcx>, Self::Error> {
+        c.try_super_fold_with(self)
+    }
+
     fn try_fold_predicate(
         &mut self,
         p: ty::Predicate<'tcx>,
@@ -345,6 +371,13 @@
         Ok(self.fold_const(c))
     }
 
+    fn try_fold_unevaluated(
+        &mut self,
+        c: ty::Unevaluated<'tcx>,
+    ) -> Result<ty::Unevaluated<'tcx>, Self::Error> {
+        Ok(self.fold_unevaluated(c))
+    }
+
     fn try_fold_predicate(
         &mut self,
         p: ty::Predicate<'tcx>,
@@ -385,13 +418,17 @@
         c.super_visit_with(self)
     }
 
-    fn visit_unevaluated_const(&mut self, uv: ty::Unevaluated<'tcx>) -> ControlFlow<Self::BreakTy> {
+    fn visit_unevaluated(&mut self, uv: ty::Unevaluated<'tcx>) -> ControlFlow<Self::BreakTy> {
         uv.super_visit_with(self)
     }
 
     fn visit_predicate(&mut self, p: ty::Predicate<'tcx>) -> ControlFlow<Self::BreakTy> {
         p.super_visit_with(self)
     }
+
+    fn visit_mir_const(&mut self, c: mir::ConstantKind<'tcx>) -> ControlFlow<Self::BreakTy> {
+        c.super_visit_with(self)
+    }
 }
 
 ///////////////////////////////////////////////////////////////////////////
@@ -514,7 +551,7 @@
                 t: &Binder<'tcx, T>,
             ) -> ControlFlow<Self::BreakTy> {
                 self.outer_index.shift_in(1);
-                let result = t.as_ref().skip_binder().visit_with(self);
+                let result = t.super_visit_with(self);
                 self.outer_index.shift_out(1);
                 result
             }
@@ -626,17 +663,17 @@
     /// the ones we have visited.
     current_index: ty::DebruijnIndex,
 
-    fld_r: Option<&'a mut (dyn FnMut(ty::BoundRegion) -> ty::Region<'tcx> + 'a)>,
-    fld_t: Option<&'a mut (dyn FnMut(ty::BoundTy) -> Ty<'tcx> + 'a)>,
-    fld_c: Option<&'a mut (dyn FnMut(ty::BoundVar, Ty<'tcx>) -> ty::Const<'tcx> + 'a)>,
+    fld_r: &'a mut (dyn FnMut(ty::BoundRegion) -> ty::Region<'tcx> + 'a),
+    fld_t: &'a mut (dyn FnMut(ty::BoundTy) -> Ty<'tcx> + 'a),
+    fld_c: &'a mut (dyn FnMut(ty::BoundVar, Ty<'tcx>) -> ty::Const<'tcx> + 'a),
 }
 
 impl<'a, 'tcx> BoundVarReplacer<'a, 'tcx> {
     fn new(
         tcx: TyCtxt<'tcx>,
-        fld_r: Option<&'a mut (dyn FnMut(ty::BoundRegion) -> ty::Region<'tcx> + 'a)>,
-        fld_t: Option<&'a mut (dyn FnMut(ty::BoundTy) -> Ty<'tcx> + 'a)>,
-        fld_c: Option<&'a mut (dyn FnMut(ty::BoundVar, Ty<'tcx>) -> ty::Const<'tcx> + 'a)>,
+        fld_r: &'a mut (dyn FnMut(ty::BoundRegion) -> ty::Region<'tcx> + 'a),
+        fld_t: &'a mut (dyn FnMut(ty::BoundTy) -> Ty<'tcx> + 'a),
+        fld_c: &'a mut (dyn FnMut(ty::BoundVar, Ty<'tcx>) -> ty::Const<'tcx> + 'a),
     ) -> Self {
         BoundVarReplacer { tcx, current_index: ty::INNERMOST, fld_r, fld_t, fld_c }
     }
@@ -660,55 +697,42 @@
     fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
         match *t.kind() {
             ty::Bound(debruijn, bound_ty) if debruijn == self.current_index => {
-                if let Some(fld_t) = self.fld_t.as_mut() {
-                    let ty = fld_t(bound_ty);
-                    return ty::fold::shift_vars(self.tcx, ty, self.current_index.as_u32());
-                }
+                let ty = (self.fld_t)(bound_ty);
+                ty::fold::shift_vars(self.tcx, ty, self.current_index.as_u32())
             }
-            _ if t.has_vars_bound_at_or_above(self.current_index) => {
-                return t.super_fold_with(self);
-            }
-            _ => {}
+            _ if t.has_vars_bound_at_or_above(self.current_index) => t.super_fold_with(self),
+            _ => t,
         }
-        t
     }
 
     fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
         match *r {
             ty::ReLateBound(debruijn, br) if debruijn == self.current_index => {
-                if let Some(fld_r) = self.fld_r.as_mut() {
-                    let region = fld_r(br);
-                    return if let ty::ReLateBound(debruijn1, br) = *region {
-                        // If the callback returns a late-bound region,
-                        // that region should always use the INNERMOST
-                        // debruijn index. Then we adjust it to the
-                        // correct depth.
-                        assert_eq!(debruijn1, ty::INNERMOST);
-                        self.tcx.mk_region(ty::ReLateBound(debruijn, br))
-                    } else {
-                        region
-                    };
+                let region = (self.fld_r)(br);
+                if let ty::ReLateBound(debruijn1, br) = *region {
+                    // If the callback returns a late-bound region,
+                    // that region should always use the INNERMOST
+                    // debruijn index. Then we adjust it to the
+                    // correct depth.
+                    assert_eq!(debruijn1, ty::INNERMOST);
+                    self.tcx.mk_region(ty::ReLateBound(debruijn, br))
+                } else {
+                    region
                 }
             }
-            _ => {}
+            _ => r,
         }
-        r
     }
 
     fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
-        match ct.val() {
+        match ct.kind() {
             ty::ConstKind::Bound(debruijn, bound_const) if debruijn == self.current_index => {
-                if let Some(fld_c) = self.fld_c.as_mut() {
-                    let ct = fld_c(bound_const, ct.ty());
-                    return ty::fold::shift_vars(self.tcx, ct, self.current_index.as_u32());
-                }
+                let ct = (self.fld_c)(bound_const, ct.ty());
+                ty::fold::shift_vars(self.tcx, ct, self.current_index.as_u32())
             }
-            _ if ct.has_vars_bound_at_or_above(self.current_index) => {
-                return ct.super_fold_with(self);
-            }
-            _ => {}
+            _ if ct.has_vars_bound_at_or_above(self.current_index) => ct.super_fold_with(self),
+            _ => ct,
         }
-        ct
     }
 }
 
@@ -722,8 +746,10 @@
     /// returned at the end with each bound region and the free region
     /// that replaced it.
     ///
-    /// This method only replaces late bound regions and the result may still
-    /// contain escaping bound types.
+    /// # Panics
+    ///
+    /// This method only replaces late bound regions. Any types or
+    /// constants bound by `value` will cause an ICE.
     pub fn replace_late_bound_regions<T, F>(
         self,
         value: Binder<'tcx, T>,
@@ -734,22 +760,35 @@
         T: TypeFoldable<'tcx>,
     {
         let mut region_map = BTreeMap::new();
-        let mut real_fld_r =
-            |br: ty::BoundRegion| *region_map.entry(br).or_insert_with(|| fld_r(br));
+        let real_fld_r = |br: ty::BoundRegion| *region_map.entry(br).or_insert_with(|| fld_r(br));
+        let value = self.replace_late_bound_regions_uncached(value, real_fld_r);
+        (value, region_map)
+    }
+
+    pub fn replace_late_bound_regions_uncached<T, F>(
+        self,
+        value: Binder<'tcx, T>,
+        mut fld_r: F,
+    ) -> T
+    where
+        F: FnMut(ty::BoundRegion) -> ty::Region<'tcx>,
+        T: TypeFoldable<'tcx>,
+    {
+        let mut fld_t = |b| bug!("unexpected bound ty in binder: {b:?}");
+        let mut fld_c = |b, ty| bug!("unexpected bound ct in binder: {b:?} {ty}");
         let value = value.skip_binder();
-        let value = if !value.has_escaping_bound_vars() {
+        if !value.has_escaping_bound_vars() {
             value
         } else {
-            let mut replacer = BoundVarReplacer::new(self, Some(&mut real_fld_r), None, None);
+            let mut replacer = BoundVarReplacer::new(self, &mut fld_r, &mut fld_t, &mut fld_c);
             value.fold_with(&mut replacer)
-        };
-        (value, region_map)
+        }
     }
 
     /// Replaces all escaping bound vars. The `fld_r` closure replaces escaping
     /// bound regions; the `fld_t` closure replaces escaping bound types and the `fld_c`
     /// closure replaces escaping bound consts.
-    pub fn replace_escaping_bound_vars<T, F, G, H>(
+    pub fn replace_escaping_bound_vars_uncached<T, F, G, H>(
         self,
         value: T,
         mut fld_r: F,
@@ -765,32 +804,28 @@
         if !value.has_escaping_bound_vars() {
             value
         } else {
-            let mut replacer =
-                BoundVarReplacer::new(self, Some(&mut fld_r), Some(&mut fld_t), Some(&mut fld_c));
+            let mut replacer = BoundVarReplacer::new(self, &mut fld_r, &mut fld_t, &mut fld_c);
             value.fold_with(&mut replacer)
         }
     }
 
     /// Replaces all types or regions bound by the given `Binder`. The `fld_r`
-    /// closure replaces bound regions while the `fld_t` closure replaces bound
-    /// types.
-    pub fn replace_bound_vars<T, F, G, H>(
+    /// closure replaces bound regions, the `fld_t` closure replaces bound
+    /// types, and `fld_c` replaces bound constants.
+    pub fn replace_bound_vars_uncached<T, F, G, H>(
         self,
         value: Binder<'tcx, T>,
-        mut fld_r: F,
+        fld_r: F,
         fld_t: G,
         fld_c: H,
-    ) -> (T, BTreeMap<ty::BoundRegion, ty::Region<'tcx>>)
+    ) -> T
     where
         F: FnMut(ty::BoundRegion) -> ty::Region<'tcx>,
         G: FnMut(ty::BoundTy) -> Ty<'tcx>,
         H: FnMut(ty::BoundVar, Ty<'tcx>) -> ty::Const<'tcx>,
         T: TypeFoldable<'tcx>,
     {
-        let mut region_map = BTreeMap::new();
-        let real_fld_r = |br: ty::BoundRegion| *region_map.entry(br).or_insert_with(|| fld_r(br));
-        let value = self.replace_escaping_bound_vars(value.skip_binder(), real_fld_r, fld_t, fld_c);
-        (value, region_map)
+        self.replace_escaping_bound_vars_uncached(value.skip_binder(), fld_r, fld_t, fld_c)
     }
 
     /// Replaces any late-bound regions bound in `value` with
@@ -803,20 +838,19 @@
     where
         T: TypeFoldable<'tcx>,
     {
-        self.replace_late_bound_regions(value, |br| {
+        self.replace_late_bound_regions_uncached(value, |br| {
             self.mk_region(ty::ReFree(ty::FreeRegion {
                 scope: all_outlive_scope,
                 bound_region: br.kind,
             }))
         })
-        .0
     }
 
     pub fn shift_bound_var_indices<T>(self, bound_vars: usize, value: T) -> T
     where
         T: TypeFoldable<'tcx>,
     {
-        self.replace_escaping_bound_vars(
+        self.replace_escaping_bound_vars_uncached(
             value,
             |r| {
                 self.mk_region(ty::ReLateBound(
@@ -838,7 +872,7 @@
             },
             |c, ty| {
                 self.mk_const(ty::ConstS {
-                    val: ty::ConstKind::Bound(
+                    kind: ty::ConstKind::Bound(
                         ty::INNERMOST,
                         ty::BoundVar::from_usize(c.as_usize() + bound_vars),
                     ),
@@ -1091,13 +1125,13 @@
     }
 
     fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
-        if let ty::ConstKind::Bound(debruijn, bound_ct) = ct.val() {
+        if let ty::ConstKind::Bound(debruijn, bound_ct) = ct.kind() {
             if self.amount == 0 || debruijn < self.current_index {
                 ct
             } else {
                 let debruijn = debruijn.shifted_in(self.amount);
                 self.tcx.mk_const(ty::ConstS {
-                    val: ty::ConstKind::Bound(debruijn, bound_ct),
+                    kind: ty::ConstKind::Bound(debruijn, bound_ct),
                     ty: ct.ty(),
                 })
             }
@@ -1207,7 +1241,7 @@
         // otherwise we do want to remember to visit the rest of the
         // const, as it has types/regions embedded in a lot of other
         // places.
-        match ct.val() {
+        match ct.kind() {
             ty::ConstKind::Bound(debruijn, _) if debruijn >= self.outer_index => {
                 ControlFlow::Break(FoundEscapingVars)
             }
@@ -1280,7 +1314,7 @@
 
     #[inline]
     #[instrument(level = "trace")]
-    fn visit_unevaluated_const(&mut self, uv: ty::Unevaluated<'tcx>) -> ControlFlow<Self::BreakTy> {
+    fn visit_unevaluated(&mut self, uv: ty::Unevaluated<'tcx>) -> ControlFlow<Self::BreakTy> {
         let flags = FlagComputation::for_unevaluated_const(uv);
         trace!(r.flags=?flags);
         if flags.intersects(self.flags) {
@@ -1362,7 +1396,7 @@
         // ignore the inputs of an unevaluated const, as they may not appear
         // in the normalized form
         if self.just_constrained {
-            if let ty::ConstKind::Unevaluated(..) = c.val() {
+            if let ty::ConstKind::Unevaluated(..) = c.kind() {
                 return ControlFlow::CONTINUE;
             }
         }
@@ -1407,7 +1441,7 @@
     }
 
     fn visit_const(&mut self, c: ty::consts::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
-        if let ty::ConstKind::Placeholder(placeholder) = c.val() {
+        if let ty::ConstKind::Placeholder(placeholder) = c.kind() {
             self.max_universe = ty::UniverseIndex::from_u32(
                 self.max_universe.as_u32().max(placeholder.universe.as_u32()),
             );
diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs
index d9b82ee..84547dc 100644
--- a/compiler/rustc_middle/src/ty/generics.rs
+++ b/compiler/rustc_middle/src/ty/generics.rs
@@ -39,6 +39,13 @@
             GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => true,
         }
     }
+
+    pub fn is_synthetic(&self) -> bool {
+        match self {
+            GenericParamDefKind::Type { synthetic, .. } => *synthetic,
+            _ => false,
+        }
+    }
 }
 
 #[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)]
@@ -63,6 +70,29 @@
             bug!("cannot convert a non-lifetime parameter def to an early bound region")
         }
     }
+
+    pub fn has_default(&self) -> bool {
+        match self.kind {
+            GenericParamDefKind::Type { has_default, .. }
+            | GenericParamDefKind::Const { has_default } => has_default,
+            GenericParamDefKind::Lifetime => false,
+        }
+    }
+
+    pub fn default_value<'tcx>(
+        &self,
+        tcx: TyCtxt<'tcx>,
+    ) -> Option<EarlyBinder<ty::GenericArg<'tcx>>> {
+        match self.kind {
+            GenericParamDefKind::Type { has_default, .. } if has_default => {
+                Some(EarlyBinder(tcx.type_of(self.def_id).into()))
+            }
+            GenericParamDefKind::Const { has_default } if has_default => {
+                Some(EarlyBinder(tcx.const_param_default(self.def_id).into()))
+            }
+            _ => None,
+        }
+    }
 }
 
 #[derive(Default)]
@@ -204,6 +234,51 @@
             matches!(param.kind, ty::GenericParamDefKind::Type { synthetic: true, .. })
         })
     }
+
+    /// Returns the substs corresponding to the generic parameters
+    /// of this item, excluding `Self`.
+    ///
+    /// **This should only be used for diagnostics purposes.**
+    pub fn own_substs_no_defaults(
+        &'tcx self,
+        tcx: TyCtxt<'tcx>,
+        substs: &'tcx [ty::GenericArg<'tcx>],
+    ) -> &'tcx [ty::GenericArg<'tcx>] {
+        let mut own_params = self.parent_count..self.count();
+        if self.has_self && self.parent.is_none() {
+            own_params.start = 1;
+        }
+
+        // Filter the default arguments.
+        //
+        // This currently uses structural equality instead
+        // of semantic equivalance. While not ideal, that's
+        // good enough for now as this should only be used
+        // for diagnostics anyways.
+        own_params.end -= self
+            .params
+            .iter()
+            .rev()
+            .take_while(|param| {
+                param.default_value(tcx).map_or(false, |default| {
+                    default.subst(tcx, substs) == substs[param.index as usize]
+                })
+            })
+            .count();
+
+        &substs[own_params]
+    }
+
+    /// Returns the substs corresponding to the generic parameters of this item, excluding `Self`.
+    ///
+    /// **This should only be used for diagnostics purposes.**
+    pub fn own_substs(
+        &'tcx self,
+        substs: &'tcx [ty::GenericArg<'tcx>],
+    ) -> &'tcx [ty::GenericArg<'tcx>] {
+        let own = &substs[self.parent_count..][..self.params.len()];
+        if self.has_self && self.parent.is_none() { &own[1..] } else { &own }
+    }
 }
 
 /// Bounds on generics.
diff --git a/compiler/rustc_middle/src/ty/impls_ty.rs b/compiler/rustc_middle/src/ty/impls_ty.rs
index 65c9b1a..88397a2 100644
--- a/compiler/rustc_middle/src/ty/impls_ty.rs
+++ b/compiler/rustc_middle/src/ty/impls_ty.rs
@@ -11,7 +11,6 @@
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey};
 use rustc_query_system::ich::StableHashingContext;
 use std::cell::RefCell;
-use std::mem;
 
 impl<'a, 'tcx, T> HashStable<StableHashingContext<'a>> for &'tcx ty::List<T>
 where
@@ -102,43 +101,12 @@
     }
 }
 
-impl<'a> HashStable<StableHashingContext<'a>> for ty::RegionKind {
+impl<'a> HashStable<StableHashingContext<'a>> for ty::EarlyBoundRegion {
+    #[inline]
     fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
-        mem::discriminant(self).hash_stable(hcx, hasher);
-        match *self {
-            ty::ReErased | ty::ReStatic => {
-                // No variant fields to hash for these ...
-            }
-            ty::ReEmpty(universe) => {
-                universe.hash_stable(hcx, hasher);
-            }
-            ty::ReLateBound(db, ty::BoundRegion { kind: ty::BrAnon(i), .. }) => {
-                db.hash_stable(hcx, hasher);
-                i.hash_stable(hcx, hasher);
-            }
-            ty::ReLateBound(db, ty::BoundRegion { kind: ty::BrNamed(def_id, name), .. }) => {
-                db.hash_stable(hcx, hasher);
-                def_id.hash_stable(hcx, hasher);
-                name.hash_stable(hcx, hasher);
-            }
-            ty::ReLateBound(db, ty::BoundRegion { kind: ty::BrEnv, .. }) => {
-                db.hash_stable(hcx, hasher);
-            }
-            ty::ReEarlyBound(ty::EarlyBoundRegion { def_id, index, name }) => {
-                def_id.hash_stable(hcx, hasher);
-                index.hash_stable(hcx, hasher);
-                name.hash_stable(hcx, hasher);
-            }
-            ty::ReFree(ref free_region) => {
-                free_region.hash_stable(hcx, hasher);
-            }
-            ty::RePlaceholder(p) => {
-                p.hash_stable(hcx, hasher);
-            }
-            ty::ReVar(..) => {
-                bug!("StableHasher: unexpected region {:?}", *self)
-            }
-        }
+        self.def_id.hash_stable(hcx, hasher);
+        self.index.hash_stable(hcx, hasher);
+        self.name.hash_stable(hcx, hasher);
     }
 }
 
diff --git a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs
index b8088766..3d22f5a 100644
--- a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs
+++ b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs
@@ -2,11 +2,12 @@
 
 use crate::ty;
 use crate::ty::context::TyCtxt;
-use crate::ty::TyKind::*;
 use crate::ty::{AdtDef, FieldDef, Ty, VariantDef};
 use crate::ty::{AdtKind, Visibility};
 use crate::ty::{DefId, SubstsRef};
 
+use rustc_type_ir::sty::TyKind::*;
+
 mod def_id_forest;
 
 // The methods in this module calculate `DefIdForest`s of modules in which an
diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs
index f088db0..e8dd179 100644
--- a/compiler/rustc_middle/src/ty/instance.rs
+++ b/compiler/rustc_middle/src/ty/instance.rs
@@ -1,7 +1,7 @@
 use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use crate::ty::print::{FmtPrinter, Printer};
 use crate::ty::subst::{InternalSubsts, Subst};
-use crate::ty::{self, EarlyBinder, SubstsRef, Ty, TyCtxt, TypeFoldable};
+use crate::ty::{self, EarlyBinder, SubstsRef, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable};
 use rustc_errors::ErrorGuaranteed;
 use rustc_hir::def::Namespace;
 use rustc_hir::def_id::{CrateNum, DefId};
@@ -369,7 +369,6 @@
     }
 
     // This should be kept up to date with `resolve`.
-    #[instrument(level = "debug", skip(tcx))]
     pub fn resolve_opt_const_arg(
         tcx: TyCtxt<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index d187146..3b05e42 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -2163,7 +2163,7 @@
         }
     }
 
-    pub fn same_size(self, other: SizeSkeleton<'_>) -> bool {
+    pub fn same_size(self, other: SizeSkeleton<'tcx>) -> bool {
         match (self, other) {
             (SizeSkeleton::Known(a), SizeSkeleton::Known(b)) => a == b,
             (SizeSkeleton::Pointer { tail: a, .. }, SizeSkeleton::Pointer { tail: b, .. }) => {
@@ -2888,6 +2888,14 @@
             return false;
         }
 
+        // With `-C panic=abort`, all non-FFI functions are required to not unwind.
+        //
+        // Note that this is true regardless ABI specified on the function -- a `extern "C-unwind"`
+        // function defined in Rust is also required to abort.
+        if tcx.sess.panic_strategy() == PanicStrategy::Abort && !tcx.is_foreign_item(did) {
+            return false;
+        }
+
         // With -Z panic-in-drop=abort, drop_in_place never unwinds.
         //
         // This is not part of `codegen_fn_attrs` as it can differ between crates
@@ -2963,7 +2971,7 @@
         | RustIntrinsic
         | PlatformIntrinsic
         | Unadjusted => false,
-        Rust | RustCall => tcx.sess.panic_strategy() == PanicStrategy::Unwind,
+        Rust | RustCall | RustCold => tcx.sess.panic_strategy() == PanicStrategy::Unwind,
     }
 }
 
@@ -2972,6 +2980,7 @@
     use rustc_target::spec::abi::Abi::*;
     match tcx.sess.target.adjust_abi(abi) {
         RustIntrinsic | PlatformIntrinsic | Rust | RustCall => Conv::Rust,
+        RustCold => Conv::RustCold,
 
         // It's the ABI's job to select this, not ours.
         System { .. } => bug!("system abi should be selected elsewhere"),
diff --git a/compiler/rustc_middle/src/ty/list.rs b/compiler/rustc_middle/src/ty/list.rs
index 197dc92..db3b5cf 100644
--- a/compiler/rustc_middle/src/ty/list.rs
+++ b/compiler/rustc_middle/src/ty/list.rs
@@ -117,15 +117,8 @@
 
 impl<S: Encoder, T: Encodable<S>> Encodable<S> for List<T> {
     #[inline]
-    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
-        (**self).encode(s)
-    }
-}
-
-impl<S: Encoder, T: Encodable<S>> Encodable<S> for &List<T> {
-    #[inline]
-    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
-        (**self).encode(s)
+    fn encode(&self, s: &mut S) {
+        (**self).encode(s);
     }
 }
 
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 1c55259..4d7aa0d 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -9,7 +9,9 @@
 //!
 //! ["The `ty` module: representing types"]: https://rustc-dev-guide.rust-lang.org/ty.html
 
-pub use self::fold::{FallibleTypeFolder, TypeFoldable, TypeFolder, TypeVisitor};
+pub use self::fold::{
+    FallibleTypeFolder, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitor,
+};
 pub use self::AssocItemContainer::*;
 pub use self::BorrowKind::*;
 pub use self::IntVarValue::*;
@@ -20,28 +22,30 @@
 use crate::traits::{self, Reveal};
 use crate::ty;
 use crate::ty::fast_reject::SimplifiedType;
-use crate::ty::subst::{GenericArg, InternalSubsts, Subst, SubstsRef};
 use crate::ty::util::Discr;
 pub use adt::*;
 pub use assoc::*;
 pub use generics::*;
 use rustc_ast as ast;
+use rustc_ast::node_id::NodeMap;
 use rustc_attr as attr;
 use rustc_data_structures::fingerprint::Fingerprint;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
+use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet};
 use rustc_data_structures::intern::{Interned, WithStableHash};
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_data_structures::tagged_ptr::CopyTaggedPtr;
 use rustc_hir as hir;
-use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
+use rustc_hir::def::{CtorKind, CtorOf, DefKind, LifetimeRes, Res};
 use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LocalDefIdMap};
 use rustc_hir::Node;
+use rustc_index::vec::IndexVec;
 use rustc_macros::HashStable;
 use rustc_query_system::ich::StableHashingContext;
-use rustc_session::cstore::CrateStoreDyn;
+use rustc_span::hygiene::MacroKind;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
-use rustc_span::Span;
-use rustc_target::abi::Align;
+use rustc_span::{ExpnId, Span};
+use rustc_target::abi::{Align, VariantIdx};
+pub use subst::*;
 pub use vtable::*;
 
 use std::fmt::Debug;
@@ -51,6 +55,8 @@
 
 pub use crate::ty::diagnostics::*;
 pub use rustc_type_ir::InferTy::*;
+pub use rustc_type_ir::RegionKind::*;
+pub use rustc_type_ir::TyKind::*;
 pub use rustc_type_ir::*;
 
 pub use self::binding::BindingMode;
@@ -72,17 +78,17 @@
 };
 pub use self::instance::{Instance, InstanceDef};
 pub use self::list::List;
+pub use self::parameterized::ParameterizedOverTcx;
+pub use self::rvalue_scopes::RvalueScopes;
 pub use self::sty::BoundRegionKind::*;
-pub use self::sty::RegionKind::*;
-pub use self::sty::TyKind::*;
 pub use self::sty::{
-    Binder, BoundRegion, BoundRegionKind, BoundTy, BoundTyKind, BoundVar, BoundVariableKind,
-    CanonicalPolyFnSig, ClosureSubsts, ClosureSubstsParts, ConstVid, EarlyBinder, EarlyBoundRegion,
-    ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, FnSig, FreeRegion, GenSig,
-    GeneratorSubsts, GeneratorSubstsParts, InlineConstSubsts, InlineConstSubstsParts, ParamConst,
-    ParamTy, PolyExistentialProjection, PolyExistentialTraitRef, PolyFnSig, PolyGenSig,
-    PolyTraitRef, ProjectionTy, Region, RegionKind, RegionVid, TraitRef, TyKind, TypeAndMut,
-    UpvarSubsts, VarianceDiagInfo,
+    Article, Binder, BoundRegion, BoundRegionKind, BoundTy, BoundTyKind, BoundVar,
+    BoundVariableKind, CanonicalPolyFnSig, ClosureSubsts, ClosureSubstsParts, ConstVid,
+    EarlyBinder, EarlyBoundRegion, ExistentialPredicate, ExistentialProjection,
+    ExistentialTraitRef, FnSig, FreeRegion, GenSig, GeneratorSubsts, GeneratorSubstsParts,
+    InlineConstSubsts, InlineConstSubstsParts, ParamConst, ParamTy, PolyExistentialProjection,
+    PolyExistentialTraitRef, PolyFnSig, PolyGenSig, PolyTraitRef, ProjectionTy, Region, RegionKind,
+    RegionVid, TraitRef, TyKind, TypeAndMut, UpvarSubsts, VarianceDiagInfo,
 };
 pub use self::trait_def::TraitDef;
 
@@ -118,6 +124,8 @@
 mod impls_ty;
 mod instance;
 mod list;
+mod parameterized;
+mod rvalue_scopes;
 mod structural_impls;
 mod sty;
 
@@ -127,14 +135,16 @@
 
 #[derive(Debug)]
 pub struct ResolverOutputs {
-    pub definitions: rustc_hir::definitions::Definitions,
-    pub cstore: Box<CrateStoreDyn>,
     pub visibilities: FxHashMap<LocalDefId, Visibility>,
     /// This field is used to decide whether we should make `PRIVATE_IN_PUBLIC` a hard error.
     pub has_pub_restricted: bool,
+    /// Item with a given `LocalDefId` was defined during macro expansion with ID `ExpnId`.
+    pub expn_that_defined: FxHashMap<LocalDefId, ExpnId>,
+    /// Reference span for definitions.
+    pub source_span: IndexVec<LocalDefId, Span>,
     pub access_levels: AccessLevels,
     pub extern_crate_map: FxHashMap<LocalDefId, CrateNum>,
-    pub maybe_unused_trait_imports: FxHashSet<LocalDefId>,
+    pub maybe_unused_trait_imports: FxIndexSet<LocalDefId>,
     pub maybe_unused_extern_crates: Vec<(LocalDefId, Span)>,
     pub reexport_map: FxHashMap<LocalDefId, Vec<ModChild>>,
     pub glob_map: FxHashMap<LocalDefId, FxHashSet<Symbol>>,
@@ -152,6 +162,34 @@
     pub registered_tools: RegisteredTools,
 }
 
+/// Resolutions that should only be used for lowering.
+/// This struct is meant to be consumed by lowering.
+#[derive(Debug)]
+pub struct ResolverAstLowering {
+    pub legacy_const_generic_args: FxHashMap<DefId, Option<Vec<usize>>>,
+
+    /// Resolutions for nodes that have a single resolution.
+    pub partial_res_map: NodeMap<hir::def::PartialRes>,
+    /// Resolutions for import nodes, which have multiple resolutions in different namespaces.
+    pub import_res_map: NodeMap<hir::def::PerNS<Option<Res<ast::NodeId>>>>,
+    /// Resolutions for labels (node IDs of their corresponding blocks or loops).
+    pub label_res_map: NodeMap<ast::NodeId>,
+    /// Resolutions for lifetimes.
+    pub lifetimes_res_map: NodeMap<LifetimeRes>,
+    /// Lifetime parameters that lowering will have to introduce.
+    pub extra_lifetime_params_map: NodeMap<Vec<(Ident, ast::NodeId, LifetimeRes)>>,
+
+    pub next_node_id: ast::NodeId,
+
+    pub node_id_to_def_id: FxHashMap<ast::NodeId, LocalDefId>,
+    pub def_id_to_node_id: IndexVec<LocalDefId, ast::NodeId>,
+
+    pub trait_map: NodeMap<Vec<hir::TraitCandidate>>,
+    /// A small map keeping true kinds of built-in macros that appear to be fn-like on
+    /// the surface (`macro` items in libcore), but are actually attributes or derives.
+    pub builtin_macro_kinds: FxHashMap<LocalDefId, MacroKind>,
+}
+
 #[derive(Clone, Copy, Debug)]
 pub struct MainDefinition {
     pub res: Res<ast::NodeId>,
@@ -227,7 +265,7 @@
     }
 }
 
-#[derive(Clone, Debug, PartialEq, Eq, Copy, Hash, TyEncodable, TyDecodable, HashStable)]
+#[derive(Clone, Debug, PartialEq, Eq, Copy, Hash, Encodable, Decodable, HashStable)]
 pub enum Visibility {
     /// Visible everywhere (including in other crates).
     Public,
@@ -409,7 +447,7 @@
 ///   of the relevant methods.
 #[derive(PartialEq, Eq, PartialOrd, Ord)]
 #[allow(rustc::usage_of_ty_tykind)]
-crate struct TyS<'tcx> {
+pub(crate) struct TyS<'tcx> {
     /// This field shouldn't be used directly and may be removed in the future.
     /// Use `Ty::kind()` instead.
     kind: TyKind<'tcx>,
@@ -459,16 +497,18 @@
 #[rustc_pass_by_value]
 pub struct Ty<'tcx>(Interned<'tcx, WithStableHash<TyS<'tcx>>>);
 
-// Statics only used for internal testing.
-pub static BOOL_TY: Ty<'static> = Ty(Interned::new_unchecked(&WithStableHash {
-    internee: BOOL_TYS,
-    stable_hash: Fingerprint::ZERO,
-}));
-const BOOL_TYS: TyS<'static> = TyS {
-    kind: ty::Bool,
-    flags: TypeFlags::empty(),
-    outer_exclusive_binder: DebruijnIndex::from_usize(0),
-};
+impl<'tcx> TyCtxt<'tcx> {
+    /// A "bool" type used in rustc_mir_transform unit tests when we
+    /// have not spun up a TyCtxt.
+    pub const BOOL_TY_FOR_UNIT_TESTING: Ty<'tcx> = Ty(Interned::new_unchecked(&WithStableHash {
+        internee: TyS {
+            kind: ty::Bool,
+            flags: TypeFlags::empty(),
+            outer_exclusive_binder: DebruijnIndex::from_usize(0),
+        },
+        stable_hash: Fingerprint::ZERO,
+    }));
+}
 
 impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for TyS<'tcx> {
     #[inline]
@@ -500,7 +540,7 @@
 /// See comments on `TyS`, which apply here too (albeit for
 /// `PredicateS`/`Predicate` rather than `TyS`/`Ty`).
 #[derive(Debug)]
-crate struct PredicateS<'tcx> {
+pub(crate) struct PredicateS<'tcx> {
     kind: Binder<'tcx, PredicateKind<'tcx>>,
     flags: TypeFlags,
     /// See the comment for the corresponding field of [TyS].
@@ -764,7 +804,7 @@
 
 impl<'tcx> TraitPredicate<'tcx> {
     pub fn remap_constness(&mut self, tcx: TyCtxt<'tcx>, param_env: &mut ParamEnv<'tcx>) {
-        if unlikely!(Some(self.trait_ref.def_id) == tcx.lang_items().drop_trait()) {
+        if std::intrinsics::unlikely(Some(self.trait_ref.def_id) == tcx.lang_items().drop_trait()) {
             // remap without changing constness of this predicate.
             // this is because `T: ~const Drop` has a different meaning to `T: Drop`
             // FIXME(fee1-dead): remove this logic after beta bump
@@ -1065,6 +1105,7 @@
     Lift
 )]
 pub struct OpaqueTypeKey<'tcx> {
+    // FIXME(oli-obk): make this a LocalDefId
     pub def_id: DefId,
     pub substs: SubstsRef<'tcx>,
 }
@@ -1121,83 +1162,6 @@
     }
 }
 
-rustc_index::newtype_index! {
-    /// "Universes" are used during type- and trait-checking in the
-    /// presence of `for<..>` binders to control what sets of names are
-    /// visible. Universes are arranged into a tree: the root universe
-    /// contains names that are always visible. Each child then adds a new
-    /// set of names that are visible, in addition to those of its parent.
-    /// We say that the child universe "extends" the parent universe with
-    /// new names.
-    ///
-    /// To make this more concrete, consider this program:
-    ///
-    /// ```ignore (illustrative)
-    /// struct Foo { }
-    /// fn bar<T>(x: T) {
-    ///   let y: for<'a> fn(&'a u8, Foo) = ...;
-    /// }
-    /// ```
-    ///
-    /// The struct name `Foo` is in the root universe U0. But the type
-    /// parameter `T`, introduced on `bar`, is in an extended universe U1
-    /// -- i.e., within `bar`, we can name both `T` and `Foo`, but outside
-    /// of `bar`, we cannot name `T`. Then, within the type of `y`, the
-    /// region `'a` is in a universe U2 that extends U1, because we can
-    /// name it inside the fn type but not outside.
-    ///
-    /// Universes are used to do type- and trait-checking around these
-    /// "forall" binders (also called **universal quantification**). The
-    /// idea is that when, in the body of `bar`, we refer to `T` as a
-    /// type, we aren't referring to any type in particular, but rather a
-    /// kind of "fresh" type that is distinct from all other types we have
-    /// actually declared. This is called a **placeholder** type, and we
-    /// use universes to talk about this. In other words, a type name in
-    /// universe 0 always corresponds to some "ground" type that the user
-    /// declared, but a type name in a non-zero universe is a placeholder
-    /// type -- an idealized representative of "types in general" that we
-    /// use for checking generic functions.
-    pub struct UniverseIndex {
-        derive [HashStable]
-        DEBUG_FORMAT = "U{}",
-    }
-}
-
-impl UniverseIndex {
-    pub const ROOT: UniverseIndex = UniverseIndex::from_u32(0);
-
-    /// Returns the "next" universe index in order -- this new index
-    /// is considered to extend all previous universes. This
-    /// corresponds to entering a `forall` quantifier. So, for
-    /// example, suppose we have this type in universe `U`:
-    ///
-    /// ```ignore (illustrative)
-    /// for<'a> fn(&'a u32)
-    /// ```
-    ///
-    /// Once we "enter" into this `for<'a>` quantifier, we are in a
-    /// new universe that extends `U` -- in this new universe, we can
-    /// name the region `'a`, but that region was not nameable from
-    /// `U` because it was not in scope there.
-    pub fn next_universe(self) -> UniverseIndex {
-        UniverseIndex::from_u32(self.private.checked_add(1).unwrap())
-    }
-
-    /// Returns `true` if `self` can name a name from `other` -- in other words,
-    /// if the set of names in `self` is a superset of those in
-    /// `other` (`self >= other`).
-    pub fn can_name(self, other: UniverseIndex) -> bool {
-        self.private >= other.private
-    }
-
-    /// Returns `true` if `self` cannot name some names from `other` -- in other
-    /// words, if the set of names in `self` is a strict subset of
-    /// those in `other` (`self < other`).
-    pub fn cannot_name(self, other: UniverseIndex) -> bool {
-        self.private < other.private
-    }
-}
-
 /// The "placeholder index" fully defines a placeholder region, type, or const. Placeholders are
 /// identified by both a universe, as well as a name residing within that universe. Distinct bound
 /// regions/types/consts within the same universe simply have an unknown relationship to one
@@ -1428,7 +1392,7 @@
 }
 
 impl<'tcx> TypeFoldable<'tcx> for ParamEnv<'tcx> {
-    fn try_super_fold_with<F: ty::fold::FallibleTypeFolder<'tcx>>(
+    fn try_fold_with<F: ty::fold::FallibleTypeFolder<'tcx>>(
         self,
         folder: &mut F,
     ) -> Result<Self, F::Error> {
@@ -1439,7 +1403,7 @@
         ))
     }
 
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         self.caller_bounds().visit_with(visitor)?;
         self.reveal().visit_with(visitor)?;
         self.constness().visit_with(visitor)
@@ -1628,7 +1592,7 @@
     }
 }
 
-#[derive(Copy, Clone, Debug, HashStable)]
+#[derive(Copy, Clone, Debug, HashStable, Encodable, Decodable)]
 pub struct Destructor {
     /// The `DefId` of the destructor method
     pub did: DefId,
@@ -1995,7 +1959,7 @@
     }
 
     /// Look up the name of a definition across crates. This does not look at HIR.
-    fn opt_item_name(self, def_id: DefId) -> Option<Symbol> {
+    pub fn opt_item_name(self, def_id: DefId) -> Option<Symbol> {
         if let Some(cnum) = def_id.as_crate_root() {
             Some(self.crate_name(cnum))
         } else {
@@ -2153,22 +2117,28 @@
     }
 
     /// Returns the possibly-auto-generated MIR of a `(DefId, Subst)` pair.
+    #[instrument(skip(self), level = "debug")]
     pub fn instance_mir(self, instance: ty::InstanceDef<'tcx>) -> &'tcx Body<'tcx> {
         match instance {
-            ty::InstanceDef::Item(def) => match self.def_kind(def.did) {
-                DefKind::Const
-                | DefKind::Static(..)
-                | DefKind::AssocConst
-                | DefKind::Ctor(..)
-                | DefKind::AnonConst
-                | DefKind::InlineConst => self.mir_for_ctfe_opt_const_arg(def),
-                // If the caller wants `mir_for_ctfe` of a function they should not be using
-                // `instance_mir`, so we'll assume const fn also wants the optimized version.
-                _ => {
-                    assert_eq!(def.const_param_did, None);
-                    self.optimized_mir(def.did)
+            ty::InstanceDef::Item(def) => {
+                debug!("calling def_kind on def: {:?}", def);
+                let def_kind = self.def_kind(def.did);
+                debug!("returned from def_kind: {:?}", def_kind);
+                match def_kind {
+                    DefKind::Const
+                    | DefKind::Static(..)
+                    | DefKind::AssocConst
+                    | DefKind::Ctor(..)
+                    | DefKind::AnonConst
+                    | DefKind::InlineConst => self.mir_for_ctfe_opt_const_arg(def),
+                    // If the caller wants `mir_for_ctfe` of a function they should not be using
+                    // `instance_mir`, so we'll assume const fn also wants the optimized version.
+                    _ => {
+                        assert_eq!(def.const_param_did, None);
+                        self.optimized_mir(def.did)
+                    }
                 }
-            },
+            }
             ty::InstanceDef::VtableShim(..)
             | ty::InstanceDef::ReifyShim(..)
             | ty::InstanceDef::Intrinsic(..)
@@ -2295,7 +2265,12 @@
     #[inline]
     pub fn is_const_fn_raw(self, def_id: DefId) -> bool {
         matches!(self.def_kind(def_id), DefKind::Fn | DefKind::AssocFn | DefKind::Ctor(..))
-            && self.impl_constness(def_id) == hir::Constness::Const
+            && self.constness(def_id) == hir::Constness::Const
+    }
+
+    #[inline]
+    pub fn is_const_default_method(self, def_id: DefId) -> bool {
+        matches!(self.trait_of_item(def_id), Some(trait_id) if self.has_attr(trait_id, sym::const_trait))
     }
 }
 
@@ -2434,3 +2409,10 @@
     /// _>::AssocType = ?T`
     pub output: bool,
 }
+
+/// The constituent parts of a type level constant of kind ADT or array.
+#[derive(Copy, Clone, Debug, HashStable)]
+pub struct DestructuredConst<'tcx> {
+    pub variant: Option<VariantIdx>,
+    pub fields: &'tcx [ty::Const<'tcx>],
+}
diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs
new file mode 100644
index 0000000..54ba9e8
--- /dev/null
+++ b/compiler/rustc_middle/src/ty/parameterized.rs
@@ -0,0 +1,119 @@
+use rustc_hir::def_id::DefId;
+use rustc_index::vec::{Idx, IndexVec};
+
+use crate::middle::exported_symbols::ExportedSymbol;
+use crate::mir::Body;
+use crate::thir::abstract_const::Node;
+use crate::ty::{
+    self, Const, FnSig, GeneratorDiagnosticData, GenericPredicates, Predicate, TraitRef, Ty,
+};
+
+pub trait ParameterizedOverTcx: 'static {
+    #[allow(unused_lifetimes)]
+    type Value<'tcx>;
+}
+
+impl<T: ParameterizedOverTcx> ParameterizedOverTcx for &'static [T] {
+    type Value<'tcx> = &'tcx [T::Value<'tcx>];
+}
+
+impl<T: ParameterizedOverTcx> ParameterizedOverTcx for Option<T> {
+    type Value<'tcx> = Option<T::Value<'tcx>>;
+}
+
+impl<A: ParameterizedOverTcx, B: ParameterizedOverTcx> ParameterizedOverTcx for (A, B) {
+    type Value<'tcx> = (A::Value<'tcx>, B::Value<'tcx>);
+}
+
+impl<I: Idx + 'static, T: ParameterizedOverTcx> ParameterizedOverTcx for IndexVec<I, T> {
+    type Value<'tcx> = IndexVec<I, T::Value<'tcx>>;
+}
+
+impl<T: ParameterizedOverTcx> ParameterizedOverTcx for ty::Binder<'static, T> {
+    type Value<'tcx> = ty::Binder<'tcx, T::Value<'tcx>>;
+}
+
+#[macro_export]
+macro_rules! trivially_parameterized_over_tcx {
+    ($($ty:ty),+ $(,)?) => {
+        $(
+            impl $crate::ty::ParameterizedOverTcx for $ty {
+                #[allow(unused_lifetimes)]
+                type Value<'tcx> = $ty;
+            }
+        )*
+    }
+}
+
+trivially_parameterized_over_tcx! {
+    usize,
+    (),
+    u32,
+    std::string::String,
+    crate::metadata::ModChild,
+    crate::middle::codegen_fn_attrs::CodegenFnAttrs,
+    crate::middle::exported_symbols::SymbolExportInfo,
+    crate::mir::ConstQualifs,
+    ty::Generics,
+    ty::ImplPolarity,
+    ty::ReprOptions,
+    ty::TraitDef,
+    ty::Visibility,
+    ty::adjustment::CoerceUnsizedInfo,
+    ty::fast_reject::SimplifiedTypeGen<DefId>,
+    rustc_ast::Attribute,
+    rustc_ast::MacArgs,
+    rustc_attr::ConstStability,
+    rustc_attr::Deprecation,
+    rustc_attr::Stability,
+    rustc_hir::Constness,
+    rustc_hir::Defaultness,
+    rustc_hir::GeneratorKind,
+    rustc_hir::IsAsync,
+    rustc_hir::LangItem,
+    rustc_hir::def::DefKind,
+    rustc_hir::def_id::DefIndex,
+    rustc_hir::definitions::DefKey,
+    rustc_index::bit_set::FiniteBitSet<u32>,
+    rustc_session::cstore::ForeignModule,
+    rustc_session::cstore::LinkagePreference,
+    rustc_session::cstore::NativeLib,
+    rustc_span::DebuggerVisualizerFile,
+    rustc_span::ExpnData,
+    rustc_span::ExpnHash,
+    rustc_span::ExpnId,
+    rustc_span::SourceFile,
+    rustc_span::Span,
+    rustc_span::Symbol,
+    rustc_span::def_id::DefPathHash,
+    rustc_span::hygiene::SyntaxContextData,
+    rustc_span::symbol::Ident,
+    rustc_type_ir::Variance,
+}
+
+// HACK(compiler-errors): This macro rule can only take an ident,
+// not a path, due to parsing ambiguity reasons. That means we gotta
+// import all of these types above.
+#[macro_export]
+macro_rules! parameterized_over_tcx {
+    ($($ident:ident),+ $(,)?) => {
+        $(
+            impl $crate::ty::ParameterizedOverTcx for $ident<'static> {
+                type Value<'tcx> = $ident<'tcx>;
+            }
+        )*
+    }
+}
+
+parameterized_over_tcx! {
+    Ty,
+    FnSig,
+    GenericPredicates,
+    TraitRef,
+    Const,
+    Predicate,
+    GeneratorDiagnosticData,
+    Body,
+    Node,
+    ExportedSymbol,
+}
diff --git a/compiler/rustc_middle/src/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs
index 9d8124e..d57cf8f 100644
--- a/compiler/rustc_middle/src/ty/print/mod.rs
+++ b/compiler/rustc_middle/src/ty/print/mod.rs
@@ -57,7 +57,7 @@
         self.default_print_impl_path(impl_def_id, substs, self_ty, trait_ref)
     }
 
-    fn print_region(self, region: ty::Region<'_>) -> Result<Self::Region, Self::Error>;
+    fn print_region(self, region: ty::Region<'tcx>) -> Result<Self::Region, Self::Error>;
 
     fn print_type(self, ty: Ty<'tcx>) -> Result<Self::Type, Self::Error>;
 
@@ -149,7 +149,7 @@
                         // on top of the same path, but without its own generics.
                         _ => {
                             if !generics.params.is_empty() && substs.len() >= generics.count() {
-                                let args = self.generic_args_to_print(generics, substs);
+                                let args = generics.own_substs_no_defaults(self.tcx(), substs);
                                 return self.path_generic_args(
                                     |cx| cx.print_def_path(def_id, parent_substs),
                                     args,
@@ -184,43 +184,6 @@
         }
     }
 
-    fn generic_args_to_print(
-        &self,
-        generics: &'tcx ty::Generics,
-        substs: &'tcx [GenericArg<'tcx>],
-    ) -> &'tcx [GenericArg<'tcx>] {
-        let mut own_params = generics.parent_count..generics.count();
-
-        // Don't print args for `Self` parameters (of traits).
-        if generics.has_self && own_params.start == 0 {
-            own_params.start = 1;
-        }
-
-        // Don't print args that are the defaults of their respective parameters.
-        own_params.end -= generics
-            .params
-            .iter()
-            .rev()
-            .take_while(|param| match param.kind {
-                ty::GenericParamDefKind::Lifetime => false,
-                ty::GenericParamDefKind::Type { has_default, .. } => {
-                    has_default
-                        && substs[param.index as usize]
-                            == GenericArg::from(
-                                self.tcx().bound_type_of(param.def_id).subst(self.tcx(), substs),
-                            )
-                }
-                ty::GenericParamDefKind::Const { has_default } => {
-                    has_default
-                        && substs[param.index as usize]
-                            == GenericArg::from(self.tcx().const_param_default(param.def_id))
-                }
-            })
-            .count();
-
-        &substs[own_params]
-    }
-
     fn default_print_impl_path(
         self,
         impl_def_id: DefId,
@@ -328,7 +291,7 @@
     characteristic_def_id_of_type_cached(ty, &mut SsoHashSet::new())
 }
 
-impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> for ty::Region<'_> {
+impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> for ty::Region<'tcx> {
     type Output = P::Region;
     type Error = P::Error;
     fn print(&self, cx: P) -> Result<Self::Output, Self::Error> {
@@ -339,6 +302,7 @@
 impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> for Ty<'tcx> {
     type Output = P::Type;
     type Error = P::Error;
+
     fn print(&self, cx: P) -> Result<Self::Output, Self::Error> {
         cx.print_type(*self)
     }
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 4c0bc2e..200253d 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -1,8 +1,11 @@
-use crate::mir::interpret::{AllocRange, ConstValue, GlobalAlloc, Pointer, Provenance, Scalar};
+use crate::mir::interpret::{AllocRange, GlobalAlloc, Pointer, Provenance, Scalar};
 use crate::ty::subst::{GenericArg, GenericArgKind, Subst};
-use crate::ty::{self, ConstInt, DefIdTree, ParamConst, ScalarInt, Term, Ty, TyCtxt, TypeFoldable};
+use crate::ty::{
+    self, ConstInt, DefIdTree, ParamConst, ScalarInt, Term, Ty, TyCtxt, TypeFoldable,
+    TypeSuperFoldable,
+};
 use rustc_apfloat::ieee::{Double, Single};
-use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
 use rustc_data_structures::sso::SsoHashSet;
 use rustc_hir as hir;
 use rustc_hir::def::{self, CtorKind, DefKind, Namespace};
@@ -179,7 +182,7 @@
     }
 
     /// Returns `Some(n)` with the number to use for the given region, if any.
-    fn region_highlighted(&self, region: ty::Region<'_>) -> Option<usize> {
+    fn region_highlighted(&self, region: ty::Region<'tcx>) -> Option<usize> {
         self.highlight_regions.iter().find_map(|h| match h {
             Some((r, n)) if *r == region => Some(*n),
             _ => None,
@@ -273,7 +276,7 @@
     /// Returns `true` if the region should be printed in
     /// optional positions, e.g., `&'a T` or `dyn Tr + 'b`.
     /// This is typically the case for all non-`'_` regions.
-    fn should_print_region(&self, region: ty::Region<'_>) -> bool;
+    fn should_print_region(&self, region: ty::Region<'tcx>) -> bool;
 
     // Defaults (should not be overridden):
 
@@ -745,14 +748,14 @@
                 p!("[", print(ty), "; ");
                 if self.tcx().sess.verbose() {
                     p!(write("{:?}", sz));
-                } else if let ty::ConstKind::Unevaluated(..) = sz.val() {
+                } else if let ty::ConstKind::Unevaluated(..) = sz.kind() {
                     // Do not try to evaluate unevaluated constants. If we are const evaluating an
                     // array length anon const, rustc will (with debug assertions) print the
                     // constant's path. Which will end up here again.
                     p!("_");
-                } else if let Some(n) = sz.val().try_to_bits(self.tcx().data_layout.pointer_size) {
+                } else if let Some(n) = sz.kind().try_to_bits(self.tcx().data_layout.pointer_size) {
                     p!(write("{}", n));
-                } else if let ty::ConstKind::Param(param) = sz.val() {
+                } else if let ty::ConstKind::Param(param) = sz.kind() {
                     p!(print(param));
                 } else {
                     p!("_");
@@ -776,8 +779,8 @@
         // by looking up the projections associated with the def_id.
         let bounds = self.tcx().bound_explicit_item_bounds(def_id);
 
-        let mut traits = BTreeMap::new();
-        let mut fn_traits = BTreeMap::new();
+        let mut traits = FxIndexMap::default();
+        let mut fn_traits = FxIndexMap::default();
         let mut is_sized = false;
 
         for predicate in bounds.transpose_iter().map(|e| e.map_bound(|(p, _)| *p)) {
@@ -822,12 +825,11 @@
 
         for (fn_once_trait_ref, entry) in fn_traits {
             // Get the (single) generic ty (the args) of this FnOnce trait ref.
-            let generics = self.generic_args_to_print(
-                self.tcx().generics_of(fn_once_trait_ref.def_id()),
-                fn_once_trait_ref.skip_binder().substs,
-            );
+            let generics = self.tcx().generics_of(fn_once_trait_ref.def_id());
+            let args =
+                generics.own_substs_no_defaults(self.tcx(), fn_once_trait_ref.skip_binder().substs);
 
-            match (entry.return_ty, generics[0].expect_ty()) {
+            match (entry.return_ty, args[0].expect_ty()) {
                 // We can only print `impl Fn() -> ()` if we have a tuple of args and we recorded
                 // a return type.
                 (Some(return_ty), arg_tys) if matches!(arg_tys.kind(), ty::Tuple(_)) => {
@@ -854,7 +856,7 @@
                     p!(")");
                     if let Term::Ty(ty) = return_ty.skip_binder() {
                         if !ty.is_unit() {
-                            p!("-> ", print(return_ty));
+                            p!(" -> ", print(return_ty));
                         }
                     }
                     p!(write("{}", if paren_needed { ")" } else { "" }));
@@ -889,15 +891,13 @@
                 print(trait_ref.skip_binder().print_only_trait_name())
             );
 
-            let generics = self.generic_args_to_print(
-                self.tcx().generics_of(trait_ref.def_id()),
-                trait_ref.skip_binder().substs,
-            );
+            let generics = self.tcx().generics_of(trait_ref.def_id());
+            let args = generics.own_substs_no_defaults(self.tcx(), trait_ref.skip_binder().substs);
 
-            if !generics.is_empty() || !assoc_items.is_empty() {
+            if !args.is_empty() || !assoc_items.is_empty() {
                 let mut first = true;
 
-                for ty in generics {
+                for ty in args {
                     if first {
                         p!("<");
                         first = false;
@@ -970,11 +970,11 @@
         &mut self,
         trait_ref: ty::PolyTraitRef<'tcx>,
         proj_ty: Option<(DefId, ty::Binder<'tcx, Term<'tcx>>)>,
-        traits: &mut BTreeMap<
+        traits: &mut FxIndexMap<
             ty::PolyTraitRef<'tcx>,
-            BTreeMap<DefId, ty::Binder<'tcx, Term<'tcx>>>,
+            FxIndexMap<DefId, ty::Binder<'tcx, Term<'tcx>>>,
         >,
-        fn_traits: &mut BTreeMap<ty::PolyTraitRef<'tcx>, OpaqueFnEntry<'tcx>>,
+        fn_traits: &mut FxIndexMap<ty::PolyTraitRef<'tcx>, OpaqueFnEntry<'tcx>>,
     ) {
         let trait_def_id = trait_ref.def_id();
 
@@ -1068,10 +1068,10 @@
                     let dummy_cx = cx.tcx().mk_ty_infer(ty::FreshTy(0));
                     let principal = principal.with_self_ty(cx.tcx(), dummy_cx);
 
-                    let args = cx.generic_args_to_print(
-                        cx.tcx().generics_of(principal.def_id),
-                        principal.substs,
-                    );
+                    let args = cx
+                        .tcx()
+                        .generics_of(principal.def_id)
+                        .own_substs_no_defaults(cx.tcx(), principal.substs);
 
                     // Don't print `'_` if there's no unerased regions.
                     let print_regions = args.iter().any(|arg| match arg.unpack() {
@@ -1110,19 +1110,18 @@
         // Builtin bounds.
         // FIXME(eddyb) avoid printing twice (needed to ensure
         // that the auto traits are sorted *and* printed via cx).
-        let mut auto_traits: Vec<_> =
-            predicates.auto_traits().map(|did| (self.tcx().def_path_str(did), did)).collect();
+        let mut auto_traits: Vec<_> = predicates.auto_traits().collect();
 
         // The auto traits come ordered by `DefPathHash`. While
         // `DefPathHash` is *stable* in the sense that it depends on
         // neither the host nor the phase of the moon, it depends
         // "pseudorandomly" on the compiler version and the target.
         //
-        // To avoid that causing instabilities in compiletest
+        // To avoid causing instabilities in compiletest
         // output, sort the auto-traits alphabetically.
-        auto_traits.sort();
+        auto_traits.sort_by_cached_key(|did| self.tcx().def_path_str(*did));
 
-        for (_, def_id) in auto_traits {
+        for def_id in auto_traits {
             if !first {
                 p!(" + ");
             }
@@ -1165,7 +1164,7 @@
         define_scoped_cx!(self);
 
         if self.tcx().sess.verbose() {
-            p!(write("Const({:?}: {:?})", ct.val(), ct.ty()));
+            p!(write("Const({:?}: {:?})", ct.kind(), ct.ty()));
             return Ok(self);
         }
 
@@ -1186,7 +1185,7 @@
             }};
         }
 
-        match ct.val() {
+        match ct.kind() {
             ty::ConstKind::Unevaluated(ty::Unevaluated {
                 def,
                 substs,
@@ -1224,7 +1223,7 @@
             }
             ty::ConstKind::Param(ParamConst { name, .. }) => p!(write("{}", name)),
             ty::ConstKind::Value(value) => {
-                return self.pretty_print_const_value(value, ct.ty(), print_ty);
+                return self.pretty_print_const_valtree(value, ct.ty(), print_ty);
             }
 
             ty::ConstKind::Bound(debruijn, bound_var) => {
@@ -1262,7 +1261,7 @@
             ty::Ref(_, inner, _) => {
                 if let ty::Array(elem, len) = inner.kind() {
                     if let ty::Uint(ty::UintTy::U8) = elem.kind() {
-                        if let ty::ConstKind::Value(ConstValue::Scalar(int)) = len.val() {
+                        if let ty::ConstKind::Value(ty::ValTree::Leaf(int)) = len.kind() {
                             match self.tcx().get_global_alloc(alloc_id) {
                                 Some(GlobalAlloc::Memory(alloc)) => {
                                     let len = int.assert_bits(self.tcx().data_layout.pointer_size);
@@ -1408,85 +1407,62 @@
         Ok(self)
     }
 
-    fn pretty_print_const_value(
+    fn pretty_print_const_valtree(
         mut self,
-        ct: ConstValue<'tcx>,
+        valtree: ty::ValTree<'tcx>,
         ty: Ty<'tcx>,
         print_ty: bool,
     ) -> Result<Self::Const, Self::Error> {
         define_scoped_cx!(self);
 
         if self.tcx().sess.verbose() {
-            p!(write("ConstValue({:?}: ", ct), print(ty), ")");
+            p!(write("ValTree({:?}: ", valtree), print(ty), ")");
             return Ok(self);
         }
 
         let u8_type = self.tcx().types.u8;
-
-        match (ct, ty.kind()) {
-            // Byte/string slices, printed as (byte) string literals.
-            (ConstValue::Slice { data, start, end }, ty::Ref(_, inner, _)) => {
-                match inner.kind() {
-                    ty::Slice(t) => {
-                        if *t == u8_type {
-                            // The `inspect` here is okay since we checked the bounds, and there are
-                            // no relocations (we have an active slice reference here). We don't use
-                            // this result to affect interpreter execution.
-                            let byte_str = data
-                                .inner()
-                                .inspect_with_uninit_and_ptr_outside_interpreter(start..end);
-                            return self.pretty_print_byte_str(byte_str);
-                        }
-                    }
-                    ty::Str => {
-                        // The `inspect` here is okay since we checked the bounds, and there are no
-                        // relocations (we have an active `str` reference here). We don't use this
-                        // result to affect interpreter execution.
-                        let slice = data
-                            .inner()
-                            .inspect_with_uninit_and_ptr_outside_interpreter(start..end);
-                        p!(write("{:?}", String::from_utf8_lossy(slice)));
-                        return Ok(self);
-                    }
-                    _ => {}
+        match (valtree, ty.kind()) {
+            (ty::ValTree::Branch(_), ty::Ref(_, inner_ty, _)) => match inner_ty.kind() {
+                ty::Slice(t) if *t == u8_type => {
+                    let bytes = valtree.try_to_raw_bytes(self.tcx(), ty).unwrap_or_else(|| {
+                        bug!(
+                            "expected to convert valtree {:?} to raw bytes for type {:?}",
+                            valtree,
+                            t
+                        )
+                    });
+                    return self.pretty_print_byte_str(bytes);
                 }
-            }
-            (ConstValue::ByRef { alloc, offset }, ty::Array(t, n)) if *t == u8_type => {
-                let n = n.val().try_to_bits(self.tcx().data_layout.pointer_size).unwrap();
-                // cast is ok because we already checked for pointer size (32 or 64 bit) above
-                let range = AllocRange { start: offset, size: Size::from_bytes(n) };
-
-                let byte_str = alloc.inner().get_bytes(&self.tcx(), range).unwrap();
+                ty::Str => {
+                    let bytes = valtree.try_to_raw_bytes(self.tcx(), ty).unwrap_or_else(|| {
+                        bug!("expected to convert valtree to raw bytes for type {:?}", ty)
+                    });
+                    p!(write("{:?}", String::from_utf8_lossy(bytes)));
+                    return Ok(self);
+                }
+                _ => {}
+            },
+            (ty::ValTree::Branch(_), ty::Array(t, _)) if *t == u8_type => {
+                let bytes = valtree.try_to_raw_bytes(self.tcx(), *t).unwrap_or_else(|| {
+                    bug!("expected to convert valtree to raw bytes for type {:?}", t)
+                });
                 p!("*");
-                p!(pretty_print_byte_str(byte_str));
+                p!(pretty_print_byte_str(bytes));
                 return Ok(self);
             }
-
             // Aggregates, printed as array/tuple/struct/variant construction syntax.
-            //
-            // NB: the `has_param_types_or_consts` check ensures that we can use
-            // the `destructure_const` query with an empty `ty::ParamEnv` without
-            // introducing ICEs (e.g. via `layout_of`) from missing bounds.
-            // E.g. `transmute([0usize; 2]): (u8, *mut T)` needs to know `T: Sized`
-            // to be able to destructure the tuple into `(0u8, *mut T)
-            //
-            // FIXME(eddyb) for `--emit=mir`/`-Z dump-mir`, we should provide the
-            // correct `ty::ParamEnv` to allow printing *all* constant values.
-            (_, ty::Array(..) | ty::Tuple(..) | ty::Adt(..)) if !ty.has_param_types_or_consts() => {
+            (ty::ValTree::Branch(_), ty::Array(..) | ty::Tuple(..) | ty::Adt(..)) => {
                 let Some(contents) = self.tcx().try_destructure_const(
-                    ty::ParamEnv::reveal_all()
-                        .and(self.tcx().mk_const(ty::ConstS { val: ty::ConstKind::Value(ct), ty })),
+                    ty::Const::from_value(self.tcx(), valtree, ty)
                 ) else {
                     // Fall back to debug pretty printing for invalid constants.
-                    p!(write("{:?}", ct));
+                    p!(write("{:?}", valtree));
                     if print_ty {
                         p!(": ", print(ty));
                     }
                     return Ok(self);
                 };
-
                 let fields = contents.fields.iter().copied();
-
                 match *ty.kind() {
                     ty::Array(..) => {
                         p!("[", comma_sep(fields), "]");
@@ -1513,7 +1489,6 @@
                             contents.variant.expect("destructed const of adt without variant idx");
                         let variant_def = &def.variant(variant_idx);
                         p!(print_value_path(variant_def.def_id, substs));
-
                         match variant_def.ctor_kind {
                             CtorKind::Const => {}
                             CtorKind::Fn => {
@@ -1535,21 +1510,22 @@
                     }
                     _ => unreachable!(),
                 }
-
                 return Ok(self);
             }
-
-            (ConstValue::Scalar(scalar), _) => {
-                return self.pretty_print_const_scalar(scalar, ty, print_ty);
+            (ty::ValTree::Leaf(leaf), _) => {
+                return self.pretty_print_const_scalar_int(leaf, ty, print_ty);
             }
-
             // FIXME(oli-obk): also pretty print arrays and other aggregate constants by reading
             // their fields instead of just dumping the memory.
             _ => {}
         }
 
         // fallback
-        p!(write("{:?}", ct));
+        if valtree == ty::ValTree::zst() {
+            p!(write("<ZST>"));
+        } else {
+            p!(write("{:?}", valtree));
+        }
         if print_ty {
             p!(": ", print(ty));
         }
@@ -1729,7 +1705,7 @@
         self.default_print_def_path(def_id, substs)
     }
 
-    fn print_region(self, region: ty::Region<'_>) -> Result<Self::Region, Self::Error> {
+    fn print_region(self, region: ty::Region<'tcx>) -> Result<Self::Region, Self::Error> {
         self.pretty_print_region(region)
     }
 
@@ -1934,7 +1910,7 @@
         Ok(inner)
     }
 
-    fn should_print_region(&self, region: ty::Region<'_>) -> bool {
+    fn should_print_region(&self, region: ty::Region<'tcx>) -> bool {
         let highlight = self.region_highlight_mode;
         if highlight.region_highlighted(region).is_some() {
             return true;
@@ -2001,8 +1977,8 @@
 }
 
 // HACK(eddyb) limited to `FmtPrinter` because of `region_highlight_mode`.
-impl FmtPrinter<'_, '_> {
-    pub fn pretty_print_region(mut self, region: ty::Region<'_>) -> Result<Self, fmt::Error> {
+impl<'tcx> FmtPrinter<'_, 'tcx> {
+    pub fn pretty_print_region(mut self, region: ty::Region<'tcx>) -> Result<Self, fmt::Error> {
         define_scoped_cx!(self);
 
         // Watch out for region highlights.
@@ -2177,61 +2153,53 @@
         define_scoped_cx!(self);
 
         let mut region_index = self.region_index;
+        let mut next_name = |this: &Self| loop {
+            let name = name_by_region_index(region_index);
+            region_index += 1;
+            if !this.used_region_names.contains(&name) {
+                break name;
+            }
+        };
+
         // If we want to print verbosely, then print *all* binders, even if they
         // aren't named. Eventually, we might just want this as the default, but
         // this is not *quite* right and changes the ordering of some output
         // anyways.
         let (new_value, map) = if self.tcx().sess.verbose() {
-            // anon index + 1 (BrEnv takes 0) -> name
-            let mut region_map: BTreeMap<u32, Symbol> = BTreeMap::default();
-            let bound_vars = value.bound_vars();
-            for var in bound_vars {
-                match var {
-                    ty::BoundVariableKind::Region(ty::BrNamed(_, name)) => {
-                        start_or_continue(&mut self, "for<", ", ");
-                        do_continue(&mut self, name);
+            let regions: Vec<_> = value
+                .bound_vars()
+                .into_iter()
+                .map(|var| {
+                    let ty::BoundVariableKind::Region(var) = var else {
+                    // This doesn't really matter because it doesn't get used,
+                    // it's just an empty value
+                    return ty::BrAnon(0);
+                };
+                    match var {
+                        ty::BrAnon(_) | ty::BrEnv => {
+                            start_or_continue(&mut self, "for<", ", ");
+                            let name = next_name(&self);
+                            do_continue(&mut self, name);
+                            ty::BrNamed(CRATE_DEF_ID.to_def_id(), name)
+                        }
+                        ty::BrNamed(def_id, kw::UnderscoreLifetime) => {
+                            start_or_continue(&mut self, "for<", ", ");
+                            let name = next_name(&self);
+                            do_continue(&mut self, name);
+                            ty::BrNamed(def_id, name)
+                        }
+                        ty::BrNamed(def_id, name) => {
+                            start_or_continue(&mut self, "for<", ", ");
+                            do_continue(&mut self, name);
+                            ty::BrNamed(def_id, name)
+                        }
                     }
-                    ty::BoundVariableKind::Region(ty::BrAnon(i)) => {
-                        start_or_continue(&mut self, "for<", ", ");
-                        let name = loop {
-                            let name = name_by_region_index(region_index);
-                            region_index += 1;
-                            if !self.used_region_names.contains(&name) {
-                                break name;
-                            }
-                        };
-                        do_continue(&mut self, name);
-                        region_map.insert(i + 1, name);
-                    }
-                    ty::BoundVariableKind::Region(ty::BrEnv) => {
-                        start_or_continue(&mut self, "for<", ", ");
-                        let name = loop {
-                            let name = name_by_region_index(region_index);
-                            region_index += 1;
-                            if !self.used_region_names.contains(&name) {
-                                break name;
-                            }
-                        };
-                        do_continue(&mut self, name);
-                        region_map.insert(0, name);
-                    }
-                    _ => continue,
-                }
-            }
+                })
+                .collect();
             start_or_continue(&mut self, "", "> ");
 
             self.tcx.replace_late_bound_regions(value.clone(), |br| {
-                let kind = match br.kind {
-                    ty::BrNamed(_, _) => br.kind,
-                    ty::BrAnon(i) => {
-                        let name = region_map[&(i + 1)];
-                        ty::BrNamed(CRATE_DEF_ID.to_def_id(), name)
-                    }
-                    ty::BrEnv => {
-                        let name = region_map[&0];
-                        ty::BrNamed(CRATE_DEF_ID.to_def_id(), name)
-                    }
-                };
+                let kind = regions[br.var.as_usize()];
                 self.tcx.mk_region(ty::ReLateBound(
                     ty::INNERMOST,
                     ty::BoundRegion { var: br.var, kind },
@@ -2242,21 +2210,20 @@
             let mut name = |br: ty::BoundRegion| {
                 start_or_continue(&mut self, "for<", ", ");
                 let kind = match br.kind {
+                    ty::BrAnon(_) | ty::BrEnv => {
+                        let name = next_name(&self);
+                        do_continue(&mut self, name);
+                        ty::BrNamed(CRATE_DEF_ID.to_def_id(), name)
+                    }
+                    ty::BrNamed(def_id, kw::UnderscoreLifetime) => {
+                        let name = next_name(&self);
+                        do_continue(&mut self, name);
+                        ty::BrNamed(def_id, name)
+                    }
                     ty::BrNamed(_, name) => {
                         do_continue(&mut self, name);
                         br.kind
                     }
-                    ty::BrAnon(_) | ty::BrEnv => {
-                        let name = loop {
-                            let name = name_by_region_index(region_index);
-                            region_index += 1;
-                            if !self.used_region_names.contains(&name) {
-                                break name;
-                            }
-                        };
-                        do_continue(&mut self, name);
-                        ty::BrNamed(CRATE_DEF_ID.to_def_id(), name)
-                    }
                 };
                 tcx.mk_region(ty::ReLateBound(ty::INNERMOST, ty::BoundRegion { var: br.var, kind }))
             };
@@ -2305,7 +2272,6 @@
         Ok(inner)
     }
 
-    #[instrument(skip(self), level = "debug")]
     fn prepare_late_bound_region_info<T>(&mut self, value: &ty::Binder<'tcx, T>)
     where
         T: TypeFoldable<'tcx>,
@@ -2318,7 +2284,6 @@
         impl<'tcx> ty::fold::TypeVisitor<'tcx> for LateBoundRegionNameCollector<'_, 'tcx> {
             type BreakTy = ();
 
-            #[instrument(skip(self), level = "trace")]
             fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
                 trace!("address: {:p}", r.0.0);
                 if let ty::ReLateBound(_, ty::BoundRegion { kind: ty::BrNamed(_, name), .. }) = *r {
@@ -2335,7 +2300,6 @@
 
             // We collect types in order to prevent really large types from compiling for
             // a really long time. See issue #83150 for why this is necessary.
-            #[instrument(skip(self), level = "trace")]
             fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
                 let not_previously_inserted = self.type_collector.insert(ty);
                 if not_previously_inserted {
@@ -2362,6 +2326,7 @@
 {
     type Output = P;
     type Error = P::Error;
+
     fn print(&self, cx: P) -> Result<Self::Output, Self::Error> {
         cx.in_binder(self)
     }
@@ -2417,15 +2382,6 @@
     };
 }
 
-// HACK(eddyb) this is separate because `ty::RegionKind` doesn't need lifting.
-impl<'tcx> fmt::Display for ty::Region<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        ty::tls::with(|tcx| {
-            f.write_str(&self.print(FmtPrinter::new(tcx, Namespace::TypeNS))?.into_buffer())
-        })
-    }
-}
-
 /// Wrapper type for `ty::TraitRef` which opts-in to pretty printing only
 /// the trait path. That is, it will print `Trait<U>` instead of
 /// `<T as Trait<U>>`.
@@ -2490,6 +2446,7 @@
 }
 
 forward_display_to_print! {
+    ty::Region<'tcx>,
     Ty<'tcx>,
     &'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>>,
     ty::Const<'tcx>,
diff --git a/compiler/rustc_middle/src/ty/query.rs b/compiler/rustc_middle/src/ty/query.rs
index fb937de..3d662ed 100644
--- a/compiler/rustc_middle/src/ty/query.rs
+++ b/compiler/rustc_middle/src/ty/query.rs
@@ -6,15 +6,14 @@
 use crate::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo};
 use crate::middle::lib_features::LibFeatures;
 use crate::middle::privacy::AccessLevels;
-use crate::middle::region;
-use crate::middle::resolve_lifetime::{
-    LifetimeScopeForPath, ObjectLifetimeDefault, Region, ResolveLifetimes,
-};
+use crate::middle::resolve_lifetime::{ObjectLifetimeDefault, Region, ResolveLifetimes};
 use crate::middle::stability::{self, DeprecationEntry};
 use crate::mir;
 use crate::mir::interpret::GlobalId;
-use crate::mir::interpret::{ConstAlloc, LitToConstError, LitToConstInput};
-use crate::mir::interpret::{ConstValue, EvalToAllocationRawResult, EvalToConstValueResult};
+use crate::mir::interpret::{
+    ConstValue, EvalToAllocationRawResult, EvalToConstValueResult, EvalToValTreeResult,
+};
+use crate::mir::interpret::{LitToConstError, LitToConstInput};
 use crate::mir::mono::CodegenUnit;
 use crate::thir;
 use crate::traits::query::{
@@ -36,7 +35,7 @@
 use rustc_ast as ast;
 use rustc_ast::expand::allocator::AllocatorKind;
 use rustc_attr as attr;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
+use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet};
 use rustc_data_structures::steal::Steal;
 use rustc_data_structures::svh::Svh;
 use rustc_data_structures::sync::Lrc;
diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs
index 8677405..51980ac 100644
--- a/compiler/rustc_middle/src/ty/relate.rs
+++ b/compiler/rustc_middle/src/ty/relate.rs
@@ -4,7 +4,6 @@
 //! types or regions but can be other things. Examples of type relations are
 //! subtyping, type equality, etc.
 
-use crate::mir::interpret::{get_slice_bytes, ConstValue, GlobalAlloc, Scalar};
 use crate::ty::error::{ExpectedFound, TypeError};
 use crate::ty::subst::{GenericArg, GenericArgKind, Subst, SubstsRef};
 use crate::ty::{self, ImplSubject, Term, Ty, TyCtxt, TypeFoldable};
@@ -579,10 +578,15 @@
     debug!("{}.super_relate_consts(a = {:?}, b = {:?})", relation.tag(), a, b);
     let tcx = relation.tcx();
 
-    // FIXME(oli-obk): once const generics can have generic types, this assertion
-    // will likely get triggered. Move to `normalize_erasing_regions` at that point.
-    let a_ty = tcx.erase_regions(a.ty());
-    let b_ty = tcx.erase_regions(b.ty());
+    let a_ty;
+    let b_ty;
+    if relation.tcx().features().adt_const_params {
+        a_ty = tcx.normalize_erasing_regions(relation.param_env(), a.ty());
+        b_ty = tcx.normalize_erasing_regions(relation.param_env(), b.ty());
+    } else {
+        a_ty = tcx.erase_regions(a.ty());
+        b_ty = tcx.erase_regions(b.ty());
+    }
     if a_ty != b_ty {
         relation.tcx().sess.delay_span_bug(
             DUMMY_SP,
@@ -597,7 +601,7 @@
     // Currently, the values that can be unified are primitive types,
     // and those that derive both `PartialEq` and `Eq`, corresponding
     // to structural-match types.
-    let is_match = match (a.val(), b.val()) {
+    let is_match = match (a.kind(), b.kind()) {
         (ty::ConstKind::Infer(_), _) | (_, ty::ConstKind::Infer(_)) => {
             // The caller should handle these cases!
             bug!("var types encountered in super_relate_consts: {:?} {:?}", a, b)
@@ -608,9 +612,7 @@
 
         (ty::ConstKind::Param(a_p), ty::ConstKind::Param(b_p)) => a_p.index == b_p.index,
         (ty::ConstKind::Placeholder(p1), ty::ConstKind::Placeholder(p2)) => p1 == p2,
-        (ty::ConstKind::Value(a_val), ty::ConstKind::Value(b_val)) => {
-            check_const_value_eq(relation, a_val, b_val, a, b)?
-        }
+        (ty::ConstKind::Value(a_val), ty::ConstKind::Value(b_val)) => a_val == b_val,
 
         (ty::ConstKind::Unevaluated(au), ty::ConstKind::Unevaluated(bu))
             if tcx.features().generic_const_exprs =>
@@ -631,7 +633,7 @@
                 bu.substs,
             )?;
             return Ok(tcx.mk_const(ty::ConstS {
-                val: ty::ConstKind::Unevaluated(ty::Unevaluated {
+                kind: ty::ConstKind::Unevaluated(ty::Unevaluated {
                     def: au.def,
                     substs,
                     promoted: au.promoted,
@@ -644,66 +646,6 @@
     if is_match { Ok(a) } else { Err(TypeError::ConstMismatch(expected_found(relation, a, b))) }
 }
 
-fn check_const_value_eq<'tcx, R: TypeRelation<'tcx>>(
-    relation: &mut R,
-    a_val: ConstValue<'tcx>,
-    b_val: ConstValue<'tcx>,
-    // FIXME(oli-obk): these arguments should go away with valtrees
-    a: ty::Const<'tcx>,
-    b: ty::Const<'tcx>,
-    // FIXME(oli-obk): this should just be `bool` with valtrees
-) -> RelateResult<'tcx, bool> {
-    let tcx = relation.tcx();
-    Ok(match (a_val, b_val) {
-        (ConstValue::Scalar(Scalar::Int(a_val)), ConstValue::Scalar(Scalar::Int(b_val))) => {
-            a_val == b_val
-        }
-        (
-            ConstValue::Scalar(Scalar::Ptr(a_val, _a_size)),
-            ConstValue::Scalar(Scalar::Ptr(b_val, _b_size)),
-        ) => {
-            a_val == b_val
-                || match (tcx.global_alloc(a_val.provenance), tcx.global_alloc(b_val.provenance)) {
-                    (GlobalAlloc::Function(a_instance), GlobalAlloc::Function(b_instance)) => {
-                        a_instance == b_instance
-                    }
-                    _ => false,
-                }
-        }
-
-        (ConstValue::Slice { .. }, ConstValue::Slice { .. }) => {
-            get_slice_bytes(&tcx, a_val) == get_slice_bytes(&tcx, b_val)
-        }
-
-        (ConstValue::ByRef { alloc: alloc_a, .. }, ConstValue::ByRef { alloc: alloc_b, .. })
-            if a.ty().is_ref() || b.ty().is_ref() =>
-        {
-            if a.ty().is_ref() && b.ty().is_ref() {
-                alloc_a == alloc_b
-            } else {
-                false
-            }
-        }
-        (ConstValue::ByRef { .. }, ConstValue::ByRef { .. }) => {
-            let a_destructured = tcx.destructure_const(relation.param_env().and(a));
-            let b_destructured = tcx.destructure_const(relation.param_env().and(b));
-
-            // Both the variant and each field have to be equal.
-            if a_destructured.variant == b_destructured.variant {
-                for (a_field, b_field) in iter::zip(a_destructured.fields, b_destructured.fields) {
-                    relation.consts(*a_field, *b_field)?;
-                }
-
-                true
-            } else {
-                false
-            }
-        }
-
-        _ => false,
-    })
-}
-
 impl<'tcx> Relate<'tcx> for &'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>> {
     fn relate<R: TypeRelation<'tcx>>(
         relation: &mut R,
diff --git a/compiler/rustc_middle/src/ty/rvalue_scopes.rs b/compiler/rustc_middle/src/ty/rvalue_scopes.rs
new file mode 100644
index 0000000..e86dafa
--- /dev/null
+++ b/compiler/rustc_middle/src/ty/rvalue_scopes.rs
@@ -0,0 +1,57 @@
+use crate::middle::region::{Scope, ScopeData, ScopeTree};
+use rustc_data_structures::fx::FxHashMap;
+use rustc_hir as hir;
+
+/// `RvalueScopes` is a mapping from sub-expressions to _extended_ lifetime as determined by
+/// rules laid out in `rustc_typeck::check::rvalue_scopes`.
+#[derive(TyEncodable, TyDecodable, Clone, Debug, Default, Eq, PartialEq, HashStable)]
+pub struct RvalueScopes {
+    map: FxHashMap<hir::ItemLocalId, Option<Scope>>,
+}
+
+impl RvalueScopes {
+    pub fn new() -> Self {
+        Self { map: <_>::default() }
+    }
+
+    /// Returns the scope when the temp created by `expr_id` will be cleaned up.
+    pub fn temporary_scope(
+        &self,
+        region_scope_tree: &ScopeTree,
+        expr_id: hir::ItemLocalId,
+    ) -> Option<Scope> {
+        // Check for a designated rvalue scope.
+        if let Some(&s) = self.map.get(&expr_id) {
+            debug!("temporary_scope({expr_id:?}) = {s:?} [custom]");
+            return s;
+        }
+
+        // Otherwise, locate the innermost terminating scope
+        // if there's one. Static items, for instance, won't
+        // have an enclosing scope, hence no scope will be
+        // returned.
+        let mut id = Scope { id: expr_id, data: ScopeData::Node };
+
+        while let Some(&(p, _)) = region_scope_tree.parent_map.get(&id) {
+            match p.data {
+                ScopeData::Destruction => {
+                    debug!("temporary_scope({expr_id:?}) = {id:?} [enclosing]");
+                    return Some(id);
+                }
+                _ => id = p,
+            }
+        }
+
+        debug!("temporary_scope({expr_id:?}) = None");
+        None
+    }
+
+    /// Make an association between a sub-expression and an extended lifetime
+    pub fn record_rvalue_scope(&mut self, var: hir::ItemLocalId, lifetime: Option<Scope>) {
+        debug!("record_rvalue_scope(var={var:?}, lifetime={lifetime:?})");
+        if let Some(lifetime) = lifetime {
+            assert!(var != lifetime.item_local_id());
+        }
+        self.map.insert(var, lifetime);
+    }
+}
diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs
index 2c8cd4f..8ba5b88 100644
--- a/compiler/rustc_middle/src/ty/structural_impls.rs
+++ b/compiler/rustc_middle/src/ty/structural_impls.rs
@@ -4,7 +4,7 @@
 
 use crate::mir::interpret;
 use crate::mir::ProjectionKind;
-use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeVisitor};
+use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable, TypeVisitor};
 use crate::ty::print::{with_no_trimmed_paths, FmtPrinter, Printer};
 use crate::ty::{self, InferConst, Lift, Term, Ty, TyCtxt};
 use rustc_data_structures::functor::IdFunctor;
@@ -81,30 +81,6 @@
     }
 }
 
-impl fmt::Debug for ty::RegionKind {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match *self {
-            ty::ReEarlyBound(ref data) => write!(f, "ReEarlyBound({}, {})", data.index, data.name),
-
-            ty::ReLateBound(binder_id, ref bound_region) => {
-                write!(f, "ReLateBound({:?}, {:?})", binder_id, bound_region)
-            }
-
-            ty::ReFree(ref fr) => fr.fmt(f),
-
-            ty::ReStatic => write!(f, "ReStatic"),
-
-            ty::ReVar(ref vid) => vid.fmt(f),
-
-            ty::RePlaceholder(placeholder) => write!(f, "RePlaceholder({:?})", placeholder),
-
-            ty::ReEmpty(ui) => write!(f, "ReEmpty({:?})", ui),
-
-            ty::ReErased => write!(f, "ReErased"),
-        }
-    }
-}
-
 impl fmt::Debug for ty::FreeRegion {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         write!(f, "ReFree({:?}, {:?})", self.scope, self.bound_region)
@@ -672,27 +648,24 @@
 
 /// AdtDefs are basically the same as a DefId.
 impl<'tcx> TypeFoldable<'tcx> for ty::AdtDef<'tcx> {
-    fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
-        self,
-        _folder: &mut F,
-    ) -> Result<Self, F::Error> {
+    fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, _folder: &mut F) -> Result<Self, F::Error> {
         Ok(self)
     }
 
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _visitor: &mut V) -> ControlFlow<V::BreakTy> {
+    fn visit_with<V: TypeVisitor<'tcx>>(&self, _visitor: &mut V) -> ControlFlow<V::BreakTy> {
         ControlFlow::CONTINUE
     }
 }
 
 impl<'tcx, T: TypeFoldable<'tcx>, U: TypeFoldable<'tcx>> TypeFoldable<'tcx> for (T, U) {
-    fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+    fn try_fold_with<F: FallibleTypeFolder<'tcx>>(
         self,
         folder: &mut F,
     ) -> Result<(T, U), F::Error> {
         Ok((self.0.try_fold_with(folder)?, self.1.try_fold_with(folder)?))
     }
 
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         self.0.visit_with(visitor)?;
         self.1.visit_with(visitor)
     }
@@ -701,7 +674,7 @@
 impl<'tcx, A: TypeFoldable<'tcx>, B: TypeFoldable<'tcx>, C: TypeFoldable<'tcx>> TypeFoldable<'tcx>
     for (A, B, C)
 {
-    fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+    fn try_fold_with<F: FallibleTypeFolder<'tcx>>(
         self,
         folder: &mut F,
     ) -> Result<(A, B, C), F::Error> {
@@ -712,7 +685,7 @@
         ))
     }
 
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         self.0.visit_with(visitor)?;
         self.1.visit_with(visitor)?;
         self.2.visit_with(visitor)
@@ -734,7 +707,7 @@
 }
 
 impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Rc<T> {
-    fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+    fn try_fold_with<F: FallibleTypeFolder<'tcx>>(
         mut self,
         folder: &mut F,
     ) -> Result<Self, F::Error> {
@@ -772,13 +745,13 @@
         }
     }
 
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         (**self).visit_with(visitor)
     }
 }
 
 impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Arc<T> {
-    fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+    fn try_fold_with<F: FallibleTypeFolder<'tcx>>(
         mut self,
         folder: &mut F,
     ) -> Result<Self, F::Error> {
@@ -816,123 +789,96 @@
         }
     }
 
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         (**self).visit_with(visitor)
     }
 }
 
 impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Box<T> {
-    fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
-        self,
-        folder: &mut F,
-    ) -> Result<Self, F::Error> {
+    fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
         self.try_map_id(|value| value.try_fold_with(folder))
     }
 
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         (**self).visit_with(visitor)
     }
 }
 
 impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Vec<T> {
-    fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
-        self,
-        folder: &mut F,
-    ) -> Result<Self, F::Error> {
+    fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
         self.try_map_id(|t| t.try_fold_with(folder))
     }
 
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         self.iter().try_for_each(|t| t.visit_with(visitor))
     }
 }
 
 impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Box<[T]> {
-    fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
-        self,
-        folder: &mut F,
-    ) -> Result<Self, F::Error> {
+    fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
         self.try_map_id(|t| t.try_fold_with(folder))
     }
 
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         self.iter().try_for_each(|t| t.visit_with(visitor))
     }
 }
 
 impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::EarlyBinder<T> {
-    fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
-        self,
-        folder: &mut F,
-    ) -> Result<Self, F::Error> {
-        self.try_map_bound(|ty| ty.try_fold_with(folder))
-    }
-
     fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
         self.try_map_bound(|ty| ty.try_fold_with(folder))
     }
 
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
-        self.as_ref().0.visit_with(visitor)
-    }
-
     fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         self.as_ref().0.visit_with(visitor)
     }
 }
 
 impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::Binder<'tcx, T> {
-    fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
-        self,
-        folder: &mut F,
-    ) -> Result<Self, F::Error> {
-        self.try_map_bound(|ty| ty.try_fold_with(folder))
-    }
-
     fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
         folder.try_fold_binder(self)
     }
 
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
-        self.as_ref().skip_binder().visit_with(visitor)
-    }
-
     fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         visitor.visit_binder(self)
     }
 }
 
-impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>> {
+impl<'tcx, T: TypeFoldable<'tcx>> TypeSuperFoldable<'tcx> for ty::Binder<'tcx, T> {
     fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
         self,
         folder: &mut F,
     ) -> Result<Self, F::Error> {
-        ty::util::fold_list(self, folder, |tcx, v| tcx.intern_poly_existential_predicates(v))
+        self.try_map_bound(|ty| ty.try_fold_with(folder))
     }
 
     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+        self.as_ref().skip_binder().visit_with(visitor)
+    }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>> {
+    fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+        ty::util::fold_list(self, folder, |tcx, v| tcx.intern_poly_existential_predicates(v))
+    }
+
+    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         self.iter().try_for_each(|p| p.visit_with(visitor))
     }
 }
 
 impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<ProjectionKind> {
-    fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
-        self,
-        folder: &mut F,
-    ) -> Result<Self, F::Error> {
+    fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
         ty::util::fold_list(self, folder, |tcx, v| tcx.intern_projs(v))
     }
 
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         self.iter().try_for_each(|t| t.visit_with(visitor))
     }
 }
 
 impl<'tcx> TypeFoldable<'tcx> for ty::instance::Instance<'tcx> {
-    fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
-        self,
-        folder: &mut F,
-    ) -> Result<Self, F::Error> {
+    fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
         use crate::ty::InstanceDef::*;
         Ok(Self {
             substs: self.substs.try_fold_with(folder)?,
@@ -958,7 +904,7 @@
         })
     }
 
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         use crate::ty::InstanceDef::*;
         self.substs.visit_with(visitor)?;
         match self.def {
@@ -980,19 +926,26 @@
 }
 
 impl<'tcx> TypeFoldable<'tcx> for interpret::GlobalId<'tcx> {
-    fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
-        self,
-        folder: &mut F,
-    ) -> Result<Self, F::Error> {
+    fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
         Ok(Self { instance: self.instance.try_fold_with(folder)?, promoted: self.promoted })
     }
 
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         self.instance.visit_with(visitor)
     }
 }
 
 impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> {
+    fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+        folder.try_fold_ty(self)
+    }
+
+    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+        visitor.visit_ty(*self)
+    }
+}
+
+impl<'tcx> TypeSuperFoldable<'tcx> for Ty<'tcx> {
     fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
         self,
         folder: &mut F,
@@ -1037,10 +990,6 @@
         Ok(if *self.kind() == kind { self } else { folder.tcx().mk_ty(kind) })
     }
 
-    fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
-        folder.try_fold_ty(self)
-    }
-
     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         match self.kind() {
             ty::RawPtr(ref tm) => tm.visit_with(visitor),
@@ -1082,50 +1031,36 @@
             | ty::Foreign(..) => ControlFlow::CONTINUE,
         }
     }
-
-    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
-        visitor.visit_ty(*self)
-    }
 }
 
 impl<'tcx> TypeFoldable<'tcx> for ty::Region<'tcx> {
-    fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
-        self,
-        _folder: &mut F,
-    ) -> Result<Self, F::Error> {
-        Ok(self)
-    }
-
     fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
         folder.try_fold_region(self)
     }
 
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _visitor: &mut V) -> ControlFlow<V::BreakTy> {
-        ControlFlow::CONTINUE
-    }
-
     fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         visitor.visit_region(*self)
     }
 }
 
+impl<'tcx> TypeSuperFoldable<'tcx> for ty::Region<'tcx> {
+    fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+        self,
+        _folder: &mut F,
+    ) -> Result<Self, F::Error> {
+        Ok(self)
+    }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _visitor: &mut V) -> ControlFlow<V::BreakTy> {
+        ControlFlow::CONTINUE
+    }
+}
+
 impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> {
     fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
         folder.try_fold_predicate(self)
     }
 
-    fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
-        self,
-        folder: &mut F,
-    ) -> Result<Self, F::Error> {
-        let new = self.kind().try_fold_with(folder)?;
-        Ok(folder.tcx().reuse_or_mk_predicate(self, new))
-    }
-
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
-        self.kind().visit_with(visitor)
-    }
-
     fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         visitor.visit_predicate(*self)
     }
@@ -1139,65 +1074,72 @@
     }
 }
 
-impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<ty::Predicate<'tcx>> {
+impl<'tcx> TypeSuperFoldable<'tcx> for ty::Predicate<'tcx> {
     fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
         self,
         folder: &mut F,
     ) -> Result<Self, F::Error> {
-        ty::util::fold_list(self, folder, |tcx, v| tcx.intern_predicates(v))
+        let new = self.kind().try_fold_with(folder)?;
+        Ok(folder.tcx().reuse_or_mk_predicate(self, new))
     }
 
     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+        self.kind().visit_with(visitor)
+    }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<ty::Predicate<'tcx>> {
+    fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+        ty::util::fold_list(self, folder, |tcx, v| tcx.intern_predicates(v))
+    }
+
+    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         self.iter().try_for_each(|p| p.visit_with(visitor))
     }
 }
 
 impl<'tcx, T: TypeFoldable<'tcx>, I: Idx> TypeFoldable<'tcx> for IndexVec<I, T> {
-    fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
-        self,
-        folder: &mut F,
-    ) -> Result<Self, F::Error> {
+    fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
         self.try_map_id(|x| x.try_fold_with(folder))
     }
 
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         self.iter().try_for_each(|t| t.visit_with(visitor))
     }
 }
 
 impl<'tcx> TypeFoldable<'tcx> for ty::Const<'tcx> {
-    fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
-        self,
-        folder: &mut F,
-    ) -> Result<Self, F::Error> {
-        let ty = self.ty().try_fold_with(folder)?;
-        let val = self.val().try_fold_with(folder)?;
-        if ty != self.ty() || val != self.val() {
-            Ok(folder.tcx().mk_const(ty::ConstS { ty, val }))
-        } else {
-            Ok(self)
-        }
-    }
-
     fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
         folder.try_fold_const(self)
     }
 
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
-        self.ty().visit_with(visitor)?;
-        self.val().visit_with(visitor)
-    }
-
     fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         visitor.visit_const(*self)
     }
 }
 
-impl<'tcx> TypeFoldable<'tcx> for ty::ConstKind<'tcx> {
+impl<'tcx> TypeSuperFoldable<'tcx> for ty::Const<'tcx> {
     fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
         self,
         folder: &mut F,
     ) -> Result<Self, F::Error> {
+        let ty = self.ty().try_fold_with(folder)?;
+        let kind = self.kind().try_fold_with(folder)?;
+        if ty != self.ty() || kind != self.kind() {
+            Ok(folder.tcx().mk_const(ty::ConstS { ty, kind }))
+        } else {
+            Ok(self)
+        }
+    }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+        self.ty().visit_with(visitor)?;
+        self.kind().visit_with(visitor)
+    }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for ty::ConstKind<'tcx> {
+    fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
         Ok(match self {
             ty::ConstKind::Infer(ic) => ty::ConstKind::Infer(ic.try_fold_with(folder)?),
             ty::ConstKind::Param(p) => ty::ConstKind::Param(p.try_fold_with(folder)?),
@@ -1209,7 +1151,7 @@
         })
     }
 
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         match *self {
             ty::ConstKind::Infer(ic) => ic.visit_with(visitor),
             ty::ConstKind::Param(p) => p.visit_with(visitor),
@@ -1223,19 +1165,26 @@
 }
 
 impl<'tcx> TypeFoldable<'tcx> for InferConst<'tcx> {
-    fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
-        self,
-        _folder: &mut F,
-    ) -> Result<Self, F::Error> {
+    fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, _folder: &mut F) -> Result<Self, F::Error> {
         Ok(self)
     }
 
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _visitor: &mut V) -> ControlFlow<V::BreakTy> {
+    fn visit_with<V: TypeVisitor<'tcx>>(&self, _visitor: &mut V) -> ControlFlow<V::BreakTy> {
         ControlFlow::CONTINUE
     }
 }
 
 impl<'tcx> TypeFoldable<'tcx> for ty::Unevaluated<'tcx> {
+    fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+        folder.try_fold_unevaluated(self)
+    }
+
+    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+        visitor.visit_unevaluated(*self)
+    }
+}
+
+impl<'tcx> TypeSuperFoldable<'tcx> for ty::Unevaluated<'tcx> {
     fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
         self,
         folder: &mut F,
@@ -1247,42 +1196,27 @@
         })
     }
 
-    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
-        visitor.visit_unevaluated_const(*self)
-    }
-
     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         self.substs.visit_with(visitor)
     }
 }
 
 impl<'tcx> TypeFoldable<'tcx> for ty::Unevaluated<'tcx, ()> {
-    fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
-        self,
-        folder: &mut F,
-    ) -> Result<Self, F::Error> {
-        Ok(ty::Unevaluated {
-            def: self.def,
-            substs: self.substs.try_fold_with(folder)?,
-            promoted: self.promoted,
-        })
+    fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+        Ok(self.expand().try_fold_with(folder)?.shrink())
     }
 
     fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
-        visitor.visit_unevaluated_const(self.expand())
-    }
-
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
-        self.substs.visit_with(visitor)
+        self.expand().visit_with(visitor)
     }
 }
 
 impl<'tcx> TypeFoldable<'tcx> for hir::Constness {
-    fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(self, _: &mut F) -> Result<Self, F::Error> {
+    fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, _: &mut F) -> Result<Self, F::Error> {
         Ok(self)
     }
 
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<V::BreakTy> {
+    fn visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<V::BreakTy> {
         ControlFlow::CONTINUE
     }
 }
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index a973a5c..296442e 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -2,16 +2,15 @@
 
 #![allow(rustc::usage_of_ty_tykind)]
 
-use self::TyKind::*;
-
 use crate::infer::canonical::Canonical;
 use crate::ty::fold::ValidateBoundVars;
 use crate::ty::subst::{GenericArg, InternalSubsts, Subst, SubstsRef};
-use crate::ty::InferTy::{self, *};
+use crate::ty::InferTy::*;
 use crate::ty::{
-    self, AdtDef, DefIdTree, Discr, Term, Ty, TyCtxt, TypeFlags, TypeFoldable, TypeVisitor,
+    self, AdtDef, DefIdTree, Discr, Term, Ty, TyCtxt, TypeFlags, TypeFoldable, TypeSuperFoldable,
+    TypeVisitor,
 };
-use crate::ty::{DelaySpanBugEmitted, List, ParamEnv};
+use crate::ty::{List, ParamEnv};
 use polonius_engine::Atom;
 use rustc_data_structures::captures::Captures;
 use rustc_data_structures::intern::Interned;
@@ -29,6 +28,15 @@
 use std::ops::{ControlFlow, Deref, Range};
 use ty::util::IntTypeExt;
 
+use rustc_type_ir::sty::TyKind::*;
+use rustc_type_ir::RegionKind as IrRegionKind;
+use rustc_type_ir::TyKind as IrTyKind;
+
+// Re-export the `TyKind` from `rustc_type_ir` here for convenience
+#[rustc_diagnostic_item = "TyKind"]
+pub type TyKind<'tcx> = IrTyKind<TyCtxt<'tcx>>;
+pub type RegionKind<'tcx> = IrRegionKind<TyCtxt<'tcx>>;
+
 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)]
 #[derive(HashStable, TypeFoldable, Lift)]
 pub struct TypeAndMut<'tcx> {
@@ -78,190 +86,13 @@
     }
 }
 
-/// Defines the kinds of types used by the type system.
-///
-/// Types written by the user start out as [hir::TyKind](rustc_hir::TyKind) and get
-/// converted to this representation using `AstConv::ast_ty_to_ty`.
-#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable, Debug)]
-#[derive(HashStable)]
-#[rustc_diagnostic_item = "TyKind"]
-pub enum TyKind<'tcx> {
-    /// The primitive boolean type. Written as `bool`.
-    Bool,
-
-    /// The primitive character type; holds a Unicode scalar value
-    /// (a non-surrogate code point). Written as `char`.
-    Char,
-
-    /// A primitive signed integer type. For example, `i32`.
-    Int(ty::IntTy),
-
-    /// A primitive unsigned integer type. For example, `u32`.
-    Uint(ty::UintTy),
-
-    /// A primitive floating-point type. For example, `f64`.
-    Float(ty::FloatTy),
-
-    /// Algebraic data types (ADT). For example: structures, enumerations and unions.
-    ///
-    /// For example, the type `List<i32>` would be represented using the `AdtDef`
-    /// for `struct List<T>` and the substs `[i32]`.
-    ///
-    /// Note that generic parameters in fields only get lazily substituted
-    /// by using something like `adt_def.all_fields().map(|field| field.ty(tcx, substs))`.
-    Adt(AdtDef<'tcx>, SubstsRef<'tcx>),
-
-    /// An unsized FFI type that is opaque to Rust. Written as `extern type T`.
-    Foreign(DefId),
-
-    /// The pointee of a string slice. Written as `str`.
-    Str,
-
-    /// An array with the given length. Written as `[T; N]`.
-    Array(Ty<'tcx>, ty::Const<'tcx>),
-
-    /// The pointee of an array slice. Written as `[T]`.
-    Slice(Ty<'tcx>),
-
-    /// A raw pointer. Written as `*mut T` or `*const T`
-    RawPtr(TypeAndMut<'tcx>),
-
-    /// A reference; a pointer with an associated lifetime. Written as
-    /// `&'a mut T` or `&'a T`.
-    Ref(Region<'tcx>, Ty<'tcx>, hir::Mutability),
-
-    /// The anonymous type of a function declaration/definition. Each
-    /// function has a unique type.
-    ///
-    /// For the function `fn foo() -> i32 { 3 }` this type would be
-    /// shown to the user as `fn() -> i32 {foo}`.
-    ///
-    /// For example the type of `bar` here:
-    /// ```rust
-    /// fn foo() -> i32 { 1 }
-    /// let bar = foo; // bar: fn() -> i32 {foo}
-    /// ```
-    FnDef(DefId, SubstsRef<'tcx>),
-
-    /// A pointer to a function. Written as `fn() -> i32`.
-    ///
-    /// Note that both functions and closures start out as either
-    /// [FnDef] or [Closure] which can be then be coerced to this variant.
-    ///
-    /// For example the type of `bar` here:
-    ///
-    /// ```rust
-    /// fn foo() -> i32 { 1 }
-    /// let bar: fn() -> i32 = foo;
-    /// ```
-    FnPtr(PolyFnSig<'tcx>),
-
-    /// A trait object. Written as `dyn for<'b> Trait<'b, Assoc = u32> + Send + 'a`.
-    Dynamic(&'tcx List<Binder<'tcx, ExistentialPredicate<'tcx>>>, ty::Region<'tcx>),
-
-    /// The anonymous type of a closure. Used to represent the type of `|a| a`.
-    ///
-    /// Closure substs contain both the - potentially substituted - generic parameters
-    /// of its parent and some synthetic parameters. See the documentation for
-    /// [ClosureSubsts] for more details.
-    Closure(DefId, SubstsRef<'tcx>),
-
-    /// The anonymous type of a generator. Used to represent the type of
-    /// `|a| yield a`.
-    ///
-    /// For more info about generator substs, visit the documentation for
-    /// [GeneratorSubsts].
-    Generator(DefId, SubstsRef<'tcx>, hir::Movability),
-
-    /// A type representing the types stored inside a generator.
-    /// This should only appear as part of the [GeneratorSubsts].
-    ///
-    /// Note that the captured variables for generators are stored separately
-    /// using a tuple in the same way as for closures.
-    ///
-    /// Unlike upvars, the witness can reference lifetimes from
-    /// inside of the generator itself. To deal with them in
-    /// the type of the generator, we convert them to higher ranked
-    /// lifetimes bound by the witness itself.
-    ///
-    /// Looking at the following example, the witness for this generator
-    /// may end up as something like `for<'a> [Vec<i32>, &'a Vec<i32>]`:
-    ///
-    /// ```ignore UNSOLVED (ask @compiler-errors, should this error? can we just swap the yields?)
-    /// #![feature(generators)]
-    /// |a| {
-    ///     let x = &vec![3];
-    ///     yield a;
-    ///     yield x[0];
-    /// }
-    /// # ;
-    /// ```
-    GeneratorWitness(Binder<'tcx, &'tcx List<Ty<'tcx>>>),
-
-    /// The never type `!`.
-    Never,
-
-    /// A tuple type. For example, `(i32, bool)`.
-    Tuple(&'tcx List<Ty<'tcx>>),
-
-    /// The projection of an associated type. For example,
-    /// `<T as Trait<..>>::N`.
-    Projection(ProjectionTy<'tcx>),
-
-    /// Opaque (`impl Trait`) type found in a return type.
-    ///
-    /// The `DefId` comes either from
-    /// * the `impl Trait` ast::Ty node,
-    /// * or the `type Foo = impl Trait` declaration
-    ///
-    /// For RPIT the substitutions are for the generics of the function,
-    /// while for TAIT it is used for the generic parameters of the alias.
-    ///
-    /// During codegen, `tcx.type_of(def_id)` can be used to get the underlying type.
-    Opaque(DefId, SubstsRef<'tcx>),
-
-    /// A type parameter; for example, `T` in `fn f<T>(x: T) {}`.
-    Param(ParamTy),
-
-    /// Bound type variable, used to represent the `'a` in `for<'a> fn(&'a ())`.
-    ///
-    /// For canonical queries, we replace inference variables with bound variables,
-    /// so e.g. when checking whether `&'_ (): Trait<_>` holds, we canonicalize that to
-    /// `for<'a, T> &'a (): Trait<T>` and then convert the introduced bound variables
-    /// back to inference variables in a new inference context when inside of the query.
-    ///
-    /// See the `rustc-dev-guide` for more details about
-    /// [higher-ranked trait bounds][1] and [canonical queries][2].
-    ///
-    /// [1]: https://rustc-dev-guide.rust-lang.org/traits/hrtb.html
-    /// [2]: https://rustc-dev-guide.rust-lang.org/traits/canonical-queries.html
-    Bound(ty::DebruijnIndex, BoundTy),
-
-    /// A placeholder type, used during higher ranked subtyping to instantiate
-    /// bound variables.
-    Placeholder(ty::PlaceholderType),
-
-    /// A type variable used during type checking.
-    ///
-    /// Similar to placeholders, inference variables also live in a universe to
-    /// correctly deal with higher ranked types. Though unlike placeholders,
-    /// that universe is stored in the `InferCtxt` instead of directly
-    /// inside of the type.
-    Infer(InferTy),
-
-    /// A placeholder for a type which could not be computed; this is
-    /// propagated to avoid useless error messages.
-    Error(DelaySpanBugEmitted),
+pub trait Article {
+    fn article(&self) -> &'static str;
 }
 
-impl<'tcx> TyKind<'tcx> {
-    #[inline]
-    pub fn is_primitive(&self) -> bool {
-        matches!(self, Bool | Char | Int(_) | Uint(_) | Float(_))
-    }
-
+impl<'tcx> Article for TyKind<'tcx> {
     /// Get the article ("a" or "an") to use with this type.
-    pub fn article(&self) -> &'static str {
+    fn article(&self) -> &'static str {
         match self {
             Int(_) | Float(_) | Array(_, _) => "an",
             Adt(def, _) if def.is_enum() => "an",
@@ -930,7 +761,7 @@
     }
 
     #[inline]
-    pub fn auto_traits<'a>(&'a self) -> impl Iterator<Item = DefId> + 'a {
+    pub fn auto_traits<'a>(&'a self) -> impl Iterator<Item = DefId> + Captures<'tcx> + 'a {
         self.iter().filter_map(|predicate| match predicate.skip_binder() {
             ExistentialPredicate::AutoTrait(did) => Some(did),
             _ => None,
@@ -1204,6 +1035,13 @@
         Binder(&self.0, self.1)
     }
 
+    pub fn as_deref(&self) -> Binder<'tcx, &T::Target>
+    where
+        T: Deref,
+    {
+        Binder(&self.0, self.1)
+    }
+
     pub fn map_bound_ref_unchecked<F, U>(&self, f: F) -> Binder<'tcx, U>
     where
         F: FnOnce(&T) -> U,
@@ -1469,15 +1307,15 @@
     }
 }
 
-/// Use this rather than `TyKind`, whenever possible.
+/// Use this rather than `RegionKind`, whenever possible.
 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable)]
 #[rustc_pass_by_value]
-pub struct Region<'tcx>(pub Interned<'tcx, RegionKind>);
+pub struct Region<'tcx>(pub Interned<'tcx, RegionKind<'tcx>>);
 
 impl<'tcx> Deref for Region<'tcx> {
-    type Target = RegionKind;
+    type Target = RegionKind<'tcx>;
 
-    fn deref(&self) -> &RegionKind {
+    fn deref(&self) -> &RegionKind<'tcx> {
         &self.0.0
     }
 }
@@ -1488,157 +1326,19 @@
     }
 }
 
-/// 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_const_eval::borrow_check`
-/// module for more information.
-///
-/// Note: operations are on the wrapper `Region` type, which is interned,
-/// rather than this type.
-///
-/// ## The Region lattice within a given function
-///
-/// In general, the region lattice looks like
-///
-/// ```text
-/// static ----------+-----...------+       (greatest)
-/// |                |              |
-/// early-bound and  |              |
-/// free regions     |              |
-/// |                |              |
-/// |                |              |
-/// empty(root)   placeholder(U1)   |
-/// |            /                  |
-/// |           /         placeholder(Un)
-/// empty(U1) --         /
-/// |                   /
-/// ...                /
-/// |                 /
-/// empty(Un) --------                      (smallest)
-/// ```
-///
-/// 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.
-///
-/// Note that inference variables and bound regions are not included
-/// in this diagram. In the case of inference variables, they should
-/// be inferred to some other region from the diagram.  In the case of
-/// bound regions, they are excluded because they don't make sense to
-/// include -- the diagram indicates the relationship between free
-/// regions.
-///
-/// ## Inference variables
-///
-/// During region inference, we sometimes create inference variables,
-/// represented as `ReVar`. These will be inferred by the code in
-/// `infer::lexical_region_resolve` to some free region from the
-/// lattice above (the minimal region that meets the
-/// constraints).
-///
-/// During NLL checking, where regions are defined differently, we
-/// also use `ReVar` -- in that case, the index is used to index into
-/// the NLL region checker's data structures. The variable may in fact
-/// represent either a free region or an inference variable, in that
-/// case.
-///
-/// ## Bound Regions
-///
-/// These are regions that are stored behind a binder and must be substituted
-/// with some concrete region before being used. There are two kind of
-/// bound regions: early-bound, which are bound in an item's `Generics`,
-/// and are substituted by an `InternalSubsts`, and late-bound, which are part of
-/// higher-ranked types (e.g., `for<'a> fn(&'a ())`), and are substituted by
-/// the likes of `liberate_late_bound_regions`. The distinction exists
-/// because higher-ranked lifetimes aren't supported in all places. See [1][2].
-///
-/// Unlike `Param`s, bound regions are not supposed to exist "in the wild"
-/// outside their binder, e.g., in types passed to type inference, and
-/// should first be substituted (by placeholder regions, free regions,
-/// or region variables).
-///
-/// ## Placeholder and Free Regions
-///
-/// One often wants to work with bound regions without knowing their precise
-/// identity. For example, when checking a function, the lifetime of a borrow
-/// can end up being assigned to some region parameter. In these cases,
-/// it must be ensured that bounds on the region can't be accidentally
-/// assumed without being checked.
-///
-/// To do this, we replace the bound regions with placeholder markers,
-/// which don't satisfy any relation not explicitly provided.
-///
-/// There are two kinds of placeholder regions in rustc: `ReFree` and
-/// `RePlaceholder`. When checking an item's body, `ReFree` is supposed
-/// to be used. These also support explicit bounds: both the internally-stored
-/// *scope*, which the region is assumed to outlive, as well as other
-/// relations stored in the `FreeRegionMap`. Note that these relations
-/// aren't checked when you `make_subregion` (or `eq_types`), only by
-/// `resolve_regions_and_report_errors`.
-///
-/// When working with higher-ranked types, some region relations aren't
-/// yet known, so you can't just call `resolve_regions_and_report_errors`.
-/// `RePlaceholder` is designed for this purpose. In these contexts,
-/// there's also the risk that some inference variable laying around will
-/// get unified with your placeholder region: if you want to check whether
-/// `for<'a> Foo<'_>: 'a`, and you substitute your bound region `'a`
-/// with a placeholder region `'%a`, the variable `'_` would just be
-/// instantiated to the placeholder region `'%a`, which is wrong because
-/// the inference variable is supposed to satisfy the relation
-/// *for every value of the placeholder region*. To ensure that doesn't
-/// happen, you can use `leak_check`. This is more clearly explained
-/// by the [rustc dev guide].
-///
-/// [1]: https://smallcultfollowing.com/babysteps/blog/2013/10/29/intermingled-parameter-lists/
-/// [2]: https://smallcultfollowing.com/babysteps/blog/2013/11/04/intermingled-parameter-lists/
-/// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/hrtb.html
-#[derive(Clone, PartialEq, Eq, Hash, Copy, TyEncodable, TyDecodable, PartialOrd, Ord)]
-pub enum RegionKind {
-    /// Region bound in a type or fn declaration which will be
-    /// substituted 'early' -- that is, at the same time when type
-    /// parameters are substituted.
-    ReEarlyBound(EarlyBoundRegion),
-
-    /// Region bound in a function scope, which will be substituted when the
-    /// function is called.
-    ReLateBound(ty::DebruijnIndex, BoundRegion),
-
-    /// When checking a function body, the types of all arguments and so forth
-    /// that refer to bound region parameters are modified to refer to free
-    /// region parameters.
-    ReFree(FreeRegion),
-
-    /// Static data that has an "infinite" lifetime. Top in the region lattice.
-    ReStatic,
-
-    /// A region variable. Should not exist outside of type inference.
-    ReVar(RegionVid),
-
-    /// A placeholder region -- basically, the higher-ranked version of `ReFree`.
-    /// Should not exist outside of type inference.
-    RePlaceholder(ty::PlaceholderRegion),
-
-    /// Empty lifetime is for data that is never accessed.  We tag the
-    /// empty lifetime with a universe -- the idea is that we don't
-    /// want `exists<'a> { forall<'b> { 'b: 'a } }` to be satisfiable.
-    /// Therefore, the `'empty` in a universe `U` is less than all
-    /// regions visible from `U`, but not less than regions not visible
-    /// from `U`.
-    ReEmpty(ty::UniverseIndex),
-
-    /// Erased region, used by trait selection, in MIR and during codegen.
-    ReErased,
-}
-
-#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Debug, PartialOrd, Ord)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, PartialOrd, Ord)]
 pub struct EarlyBoundRegion {
     pub def_id: DefId,
     pub index: u32,
     pub name: Symbol,
 }
 
+impl fmt::Debug for EarlyBoundRegion {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "{}, {}", self.index, self.name)
+    }
+}
+
 /// A **`const`** **v**ariable **ID**.
 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)]
 pub struct ConstVid<'tcx> {
@@ -1754,7 +1454,7 @@
 
 /// Region utilities
 impl<'tcx> Region<'tcx> {
-    pub fn kind(self) -> RegionKind {
+    pub fn kind(self) -> RegionKind<'tcx> {
         *self.0.0
     }
 
diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs
index 48c7111..ad2898c 100644
--- a/compiler/rustc_middle/src/ty/subst.rs
+++ b/compiler/rustc_middle/src/ty/subst.rs
@@ -2,9 +2,11 @@
 
 use crate::mir;
 use crate::ty::codec::{TyDecoder, TyEncoder};
-use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeFolder, TypeVisitor};
+use crate::ty::fold::{
+    FallibleTypeFolder, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitor,
+};
 use crate::ty::sty::{ClosureSubsts, GeneratorSubsts, InlineConstSubsts};
-use crate::ty::{self, EarlyBinder, Lift, List, ParamConst, Ty, TyCtxt};
+use crate::ty::{self, Lift, List, ParamConst, Ty, TyCtxt};
 
 use rustc_data_structures::intern::{Interned, WithStableHash};
 use rustc_hir::def_id::DefId;
@@ -79,17 +81,17 @@
         let (tag, ptr) = match self {
             GenericArgKind::Lifetime(lt) => {
                 // Ensure we can use the tag bits.
-                assert_eq!(mem::align_of_val(lt.0.0) & TAG_MASK, 0);
-                (REGION_TAG, lt.0.0 as *const ty::RegionKind as usize)
+                assert_eq!(mem::align_of_val(&*lt.0.0) & TAG_MASK, 0);
+                (REGION_TAG, lt.0.0 as *const ty::RegionKind<'tcx> as usize)
             }
             GenericArgKind::Type(ty) => {
                 // Ensure we can use the tag bits.
-                assert_eq!(mem::align_of_val(ty.0.0) & TAG_MASK, 0);
+                assert_eq!(mem::align_of_val(&*ty.0.0) & TAG_MASK, 0);
                 (TYPE_TAG, ty.0.0 as *const WithStableHash<ty::TyS<'tcx>> as usize)
             }
             GenericArgKind::Const(ct) => {
                 // Ensure we can use the tag bits.
-                assert_eq!(mem::align_of_val(ct.0.0) & TAG_MASK, 0);
+                assert_eq!(mem::align_of_val(&*ct.0.0) & TAG_MASK, 0);
                 (CONST_TAG, ct.0.0 as *const ty::ConstS<'tcx> as usize)
             }
         };
@@ -109,13 +111,13 @@
 }
 
 impl<'tcx> Ord for GenericArg<'tcx> {
-    fn cmp(&self, other: &GenericArg<'_>) -> Ordering {
+    fn cmp(&self, other: &GenericArg<'tcx>) -> Ordering {
         self.unpack().cmp(&other.unpack())
     }
 }
 
 impl<'tcx> PartialOrd for GenericArg<'tcx> {
-    fn partial_cmp(&self, other: &GenericArg<'_>) -> Option<Ordering> {
+    fn partial_cmp(&self, other: &GenericArg<'tcx>) -> Option<Ordering> {
         Some(self.cmp(&other))
     }
 }
@@ -151,7 +153,7 @@
         unsafe {
             match ptr & TAG_MASK {
                 REGION_TAG => GenericArgKind::Lifetime(ty::Region(Interned::new_unchecked(
-                    &*((ptr & !TAG_MASK) as *const ty::RegionKind),
+                    &*((ptr & !TAG_MASK) as *const ty::RegionKind<'tcx>),
                 ))),
                 TYPE_TAG => GenericArgKind::Type(Ty(Interned::new_unchecked(
                     &*((ptr & !TAG_MASK) as *const WithStableHash<ty::TyS<'tcx>>),
@@ -196,10 +198,7 @@
 }
 
 impl<'tcx> TypeFoldable<'tcx> for GenericArg<'tcx> {
-    fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
-        self,
-        folder: &mut F,
-    ) -> Result<Self, F::Error> {
+    fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
         match self.unpack() {
             GenericArgKind::Lifetime(lt) => lt.try_fold_with(folder).map(Into::into),
             GenericArgKind::Type(ty) => ty.try_fold_with(folder).map(Into::into),
@@ -207,7 +206,7 @@
         }
     }
 
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         match self.unpack() {
             GenericArgKind::Lifetime(lt) => lt.visit_with(visitor),
             GenericArgKind::Type(ty) => ty.visit_with(visitor),
@@ -216,13 +215,13 @@
     }
 }
 
-impl<'tcx, E: TyEncoder<'tcx>> Encodable<E> for GenericArg<'tcx> {
-    fn encode(&self, e: &mut E) -> Result<(), E::Error> {
+impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E> for GenericArg<'tcx> {
+    fn encode(&self, e: &mut E) {
         self.unpack().encode(e)
     }
 }
 
-impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for GenericArg<'tcx> {
+impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for GenericArg<'tcx> {
     fn decode(d: &mut D) -> GenericArg<'tcx> {
         GenericArgKind::decode(d).pack()
     }
@@ -233,7 +232,7 @@
 
 pub type SubstsRef<'tcx> = &'tcx InternalSubsts<'tcx>;
 
-impl<'a, 'tcx> InternalSubsts<'tcx> {
+impl<'tcx> InternalSubsts<'tcx> {
     /// Checks whether all elements of this list are types, if so, transmute.
     pub fn try_as_type_list(&'tcx self) -> Option<&'tcx List<Ty<'tcx>>> {
         if self.iter().all(|arg| matches!(arg.unpack(), GenericArgKind::Type(_))) {
@@ -249,7 +248,7 @@
     /// Closure substitutions have a particular structure controlled by the
     /// compiler that encodes information like the signature and closure kind;
     /// see `ty::ClosureSubsts` struct for more comments.
-    pub fn as_closure(&'a self) -> ClosureSubsts<'a> {
+    pub fn as_closure(&'tcx self) -> ClosureSubsts<'tcx> {
         ClosureSubsts { substs: self }
     }
 
@@ -330,20 +329,20 @@
     }
 
     #[inline]
-    pub fn types(&'a self) -> impl DoubleEndedIterator<Item = Ty<'tcx>> + 'a {
+    pub fn types(&'tcx self) -> impl DoubleEndedIterator<Item = Ty<'tcx>> + 'tcx {
         self.iter()
             .filter_map(|k| if let GenericArgKind::Type(ty) = k.unpack() { Some(ty) } else { None })
     }
 
     #[inline]
-    pub fn regions(&'a self) -> impl DoubleEndedIterator<Item = ty::Region<'tcx>> + 'a {
+    pub fn regions(&'tcx self) -> impl DoubleEndedIterator<Item = ty::Region<'tcx>> + 'tcx {
         self.iter().filter_map(|k| {
             if let GenericArgKind::Lifetime(lt) = k.unpack() { Some(lt) } else { None }
         })
     }
 
     #[inline]
-    pub fn consts(&'a self) -> impl DoubleEndedIterator<Item = ty::Const<'tcx>> + 'a {
+    pub fn consts(&'tcx self) -> impl DoubleEndedIterator<Item = ty::Const<'tcx>> + 'tcx {
         self.iter().filter_map(|k| {
             if let GenericArgKind::Const(ct) = k.unpack() { Some(ct) } else { None }
         })
@@ -351,8 +350,8 @@
 
     #[inline]
     pub fn non_erasable_generics(
-        &'a self,
-    ) -> impl DoubleEndedIterator<Item = GenericArgKind<'tcx>> + 'a {
+        &'tcx self,
+    ) -> impl DoubleEndedIterator<Item = GenericArgKind<'tcx>> + 'tcx {
         self.iter().filter_map(|k| match k.unpack() {
             GenericArgKind::Lifetime(_) => None,
             generic => Some(generic),
@@ -425,10 +424,7 @@
 }
 
 impl<'tcx> TypeFoldable<'tcx> for SubstsRef<'tcx> {
-    fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
-        self,
-        folder: &mut F,
-    ) -> Result<Self, F::Error> {
+    fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
         // This code is hot enough that it's worth specializing for the most
         // common length lists, to avoid the overhead of `SmallVec` creation.
         // The match arms are in order of frequency. The 1, 2, and 0 cases are
@@ -454,16 +450,13 @@
         }
     }
 
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         self.iter().try_for_each(|t| t.visit_with(visitor))
     }
 }
 
 impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<Ty<'tcx>> {
-    fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
-        self,
-        folder: &mut F,
-    ) -> Result<Self, F::Error> {
+    fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
         // This code is fairly hot, though not as hot as `SubstsRef`.
         //
         // When compiling stage 2, I get the following results:
@@ -493,7 +486,7 @@
         }
     }
 
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         self.iter().try_for_each(|t| t.visit_with(visitor))
     }
 }
@@ -506,7 +499,7 @@
     fn subst(self, tcx: TyCtxt<'tcx>, substs: &[GenericArg<'tcx>]) -> Self::Inner;
 }
 
-impl<'tcx, T: TypeFoldable<'tcx>> Subst<'tcx> for EarlyBinder<T> {
+impl<'tcx, T: TypeFoldable<'tcx>> Subst<'tcx> for ty::EarlyBinder<T> {
     type Inner = T;
 
     fn subst(self, tcx: TyCtxt<'tcx>, substs: &[GenericArg<'tcx>]) -> Self::Inner {
@@ -578,7 +571,7 @@
     }
 
     fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> {
-        if let ty::ConstKind::Param(p) = c.val() {
+        if let ty::ConstKind::Param(p) = c.kind() {
             self.const_for_param(p, c)
         } else {
             c.super_fold_with(self)
diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs
index ca6fabf..cb34b64 100644
--- a/compiler/rustc_middle/src/ty/trait_def.rs
+++ b/compiler/rustc_middle/src/ty/trait_def.rs
@@ -143,7 +143,7 @@
         self_ty: Ty<'tcx>,
     ) -> impl Iterator<Item = DefId> + 'tcx {
         let impls = self.trait_impls_of(def_id);
-        if let Some(simp) = fast_reject::simplify_type(self, self_ty, TreatParams::AsPlaceholders) {
+        if let Some(simp) = fast_reject::simplify_type(self, self_ty, TreatParams::AsInfer) {
             if let Some(impls) = impls.non_blanket_impls.get(&simp) {
                 return impls.iter().copied();
             }
@@ -173,14 +173,14 @@
             }
         }
 
-        // Note that we're using `TreatParams::AsBoundTypes` to query `non_blanket_impls` while using
-        // `TreatParams::AsPlaceholders` while actually adding them.
+        // Note that we're using `TreatParams::AsPlaceholder` to query `non_blanket_impls` while using
+        // `TreatParams::AsInfer` while actually adding them.
         //
         // This way, when searching for some impl for `T: Trait`, we do not look at any impls
         // whose outer level is not a parameter or projection. Especially for things like
         // `T: Clone` this is incredibly useful as we would otherwise look at all the impls
         // of `Clone` for `Option<T>`, `Vec<T>`, `ConcreteType` and so on.
-        if let Some(simp) = fast_reject::simplify_type(self, self_ty, TreatParams::AsBoundTypes) {
+        if let Some(simp) = fast_reject::simplify_type(self, self_ty, TreatParams::AsPlaceholder) {
             if let Some(impls) = impls.non_blanket_impls.get(&simp) {
                 for &impl_def_id in impls {
                     if let result @ Some(_) = f(impl_def_id) {
@@ -240,7 +240,7 @@
         }
 
         if let Some(simplified_self_ty) =
-            fast_reject::simplify_type(tcx, impl_self_ty, TreatParams::AsPlaceholders)
+            fast_reject::simplify_type(tcx, impl_self_ty, TreatParams::AsInfer)
         {
             impls.non_blanket_impls.entry(simplified_self_ty).or_default().push(impl_def_id);
         } else {
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index 1052067..3884603 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -1,13 +1,11 @@
 //! Miscellaneous type-system utilities that are too small to deserve their own modules.
 
 use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
-use crate::ty::fold::{FallibleTypeFolder, TypeFolder};
 use crate::ty::layout::IntegerExt;
 use crate::ty::query::TyCtxtAt;
 use crate::ty::subst::{GenericArgKind, Subst, SubstsRef};
 use crate::ty::{
-    self, Const, DebruijnIndex, DefIdTree, EarlyBinder, List, ReEarlyBound, Ty, TyCtxt, TyKind::*,
-    TypeFoldable,
+    self, DefIdTree, FallibleTypeFolder, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,
 };
 use rustc_apfloat::Float as _;
 use rustc_ast as ast;
@@ -18,9 +16,11 @@
 use rustc_hir as hir;
 use rustc_hir::def::{CtorOf, DefKind, Res};
 use rustc_hir::def_id::DefId;
+use rustc_index::bit_set::GrowableBitSet;
 use rustc_macros::HashStable;
 use rustc_span::{sym, DUMMY_SP};
 use rustc_target::abi::{Integer, Size, TargetDataLayout};
+use rustc_target::spec::abi::Abi;
 use smallvec::SmallVec;
 use std::{fmt, iter};
 
@@ -31,6 +31,19 @@
     pub ty: Ty<'tcx>,
 }
 
+/// Used as an input to [`TyCtxt::uses_unique_generic_params`].
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub enum IgnoreRegions {
+    Yes,
+    No,
+}
+
+#[derive(Copy, Clone, Debug)]
+pub enum NotUniqueParam<'tcx> {
+    DuplicateParam(ty::GenericArg<'tcx>),
+    NotParam(ty::GenericArg<'tcx>),
+}
+
 impl<'tcx> fmt::Display for Discr<'tcx> {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
         match *self.ty.kind() {
@@ -48,8 +61,8 @@
 
 fn int_size_and_signed<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> (Size, bool) {
     let (int, signed) = match *ty.kind() {
-        Int(ity) => (Integer::from_int_ty(&tcx, ity), true),
-        Uint(uty) => (Integer::from_uint_ty(&tcx, uty), false),
+        ty::Int(ity) => (Integer::from_int_ty(&tcx, ity), true),
+        ty::Uint(uty) => (Integer::from_uint_ty(&tcx, uty), false),
         _ => bug!("non integer discriminant"),
     };
     (int.size(), signed)
@@ -175,7 +188,7 @@
         if let ty::Adt(def, substs) = *ty.kind() {
             for field in def.all_fields() {
                 let field_ty = field.ty(self, substs);
-                if let Error(_) = field_ty.kind() {
+                if let ty::Error(_) = field_ty.kind() {
                     return true;
                 }
             }
@@ -310,7 +323,7 @@
         let (mut a, mut b) = (source, target);
         loop {
             match (&a.kind(), &b.kind()) {
-                (&Adt(a_def, a_substs), &Adt(b_def, b_substs))
+                (&ty::Adt(a_def, a_substs), &ty::Adt(b_def, b_substs))
                     if a_def == b_def && a_def.is_struct() =>
                 {
                     if let Some(f) = a_def.non_enum_variant().fields.last() {
@@ -320,7 +333,7 @@
                         break;
                     }
                 }
-                (&Tuple(a_tys), &Tuple(b_tys)) if a_tys.len() == b_tys.len() => {
+                (&ty::Tuple(a_tys), &ty::Tuple(b_tys)) if a_tys.len() == b_tys.len() => {
                     if let Some(&a_last) = a_tys.last() {
                         a = a_last;
                         b = *b_tys.last().unwrap();
@@ -363,7 +376,7 @@
         let (did, constness) = self.find_map_relevant_impl(drop_trait, ty, |impl_did| {
             if let Some(item_id) = self.associated_item_def_ids(impl_did).first() {
                 if validate(self, impl_did).is_ok() {
-                    return Some((*item_id, self.impl_constness(impl_did)));
+                    return Some((*item_id, self.constness(impl_did)));
                 }
             }
             None
@@ -426,7 +439,7 @@
             .filter(|&(_, k)| {
                 match k.unpack() {
                     GenericArgKind::Lifetime(region) => match region.kind() {
-                        ReEarlyBound(ref ebr) => {
+                        ty::ReEarlyBound(ref ebr) => {
                             !impl_generics.region_param(ebr, self).pure_wrt_drop
                         }
                         // Error: not a region param
@@ -437,7 +450,7 @@
                         // Error: not a type param
                         _ => false,
                     },
-                    GenericArgKind::Const(ct) => match ct.val() {
+                    GenericArgKind::Const(ct) => match ct.kind() {
                         ty::ConstKind::Param(ref pc) => {
                             !impl_generics.const_param(pc, self).pure_wrt_drop
                         }
@@ -452,6 +465,47 @@
         result
     }
 
+    /// Checks whether each generic argument is simply a unique generic parameter.
+    pub fn uses_unique_generic_params(
+        self,
+        substs: SubstsRef<'tcx>,
+        ignore_regions: IgnoreRegions,
+    ) -> Result<(), NotUniqueParam<'tcx>> {
+        let mut seen = GrowableBitSet::default();
+        for arg in substs {
+            match arg.unpack() {
+                GenericArgKind::Lifetime(lt) => {
+                    if ignore_regions == IgnoreRegions::No {
+                        let ty::ReEarlyBound(p) = lt.kind() else {
+                            return Err(NotUniqueParam::NotParam(lt.into()))
+                        };
+                        if !seen.insert(p.index) {
+                            return Err(NotUniqueParam::DuplicateParam(lt.into()));
+                        }
+                    }
+                }
+                GenericArgKind::Type(t) => match t.kind() {
+                    ty::Param(p) => {
+                        if !seen.insert(p.index) {
+                            return Err(NotUniqueParam::DuplicateParam(t.into()));
+                        }
+                    }
+                    _ => return Err(NotUniqueParam::NotParam(t.into())),
+                },
+                GenericArgKind::Const(c) => match c.kind() {
+                    ty::ConstKind::Param(p) => {
+                        if !seen.insert(p.index) {
+                            return Err(NotUniqueParam::DuplicateParam(c.into()));
+                        }
+                    }
+                    _ => return Err(NotUniqueParam::NotParam(c.into())),
+                },
+            }
+        }
+
+        Ok(())
+    }
+
     /// Returns `true` if `def_id` refers to a closure (e.g., `|x| x * 2`). Note
     /// that closures have a `DefId`, but the closure *expression* also
     /// has a `HirId` that is located within the context where the
@@ -520,7 +574,7 @@
         self,
         closure_def_id: DefId,
         closure_substs: SubstsRef<'tcx>,
-        env_region: ty::RegionKind,
+        env_region: ty::RegionKind<'tcx>,
     ) -> Option<Ty<'tcx>> {
         let closure_ty = self.mk_closure(closure_def_id, closure_substs);
         let closure_kind_ty = closure_substs.as_closure().kind_ty();
@@ -593,30 +647,33 @@
         if visitor.found_recursion { Err(expanded_type) } else { Ok(expanded_type) }
     }
 
-    pub fn bound_type_of(self, def_id: DefId) -> EarlyBinder<Ty<'tcx>> {
-        EarlyBinder(self.type_of(def_id))
+    pub fn bound_type_of(self, def_id: DefId) -> ty::EarlyBinder<Ty<'tcx>> {
+        ty::EarlyBinder(self.type_of(def_id))
     }
 
-    pub fn bound_fn_sig(self, def_id: DefId) -> EarlyBinder<ty::PolyFnSig<'tcx>> {
-        EarlyBinder(self.fn_sig(def_id))
+    pub fn bound_fn_sig(self, def_id: DefId) -> ty::EarlyBinder<ty::PolyFnSig<'tcx>> {
+        ty::EarlyBinder(self.fn_sig(def_id))
     }
 
-    pub fn bound_impl_trait_ref(self, def_id: DefId) -> Option<EarlyBinder<ty::TraitRef<'tcx>>> {
-        self.impl_trait_ref(def_id).map(|i| EarlyBinder(i))
+    pub fn bound_impl_trait_ref(
+        self,
+        def_id: DefId,
+    ) -> Option<ty::EarlyBinder<ty::TraitRef<'tcx>>> {
+        self.impl_trait_ref(def_id).map(|i| ty::EarlyBinder(i))
     }
 
     pub fn bound_explicit_item_bounds(
         self,
         def_id: DefId,
-    ) -> EarlyBinder<&'tcx [(ty::Predicate<'tcx>, rustc_span::Span)]> {
-        EarlyBinder(self.explicit_item_bounds(def_id))
+    ) -> ty::EarlyBinder<&'tcx [(ty::Predicate<'tcx>, rustc_span::Span)]> {
+        ty::EarlyBinder(self.explicit_item_bounds(def_id))
     }
 
     pub fn bound_item_bounds(
         self,
         def_id: DefId,
-    ) -> EarlyBinder<&'tcx ty::List<ty::Predicate<'tcx>>> {
-        EarlyBinder(self.item_bounds(def_id))
+    ) -> ty::EarlyBinder<&'tcx ty::List<ty::Predicate<'tcx>>> {
+        ty::EarlyBinder(self.item_bounds(def_id))
     }
 }
 
@@ -689,7 +746,7 @@
 impl<'tcx> Ty<'tcx> {
     /// Returns the maximum value for the given numeric type (including `char`s)
     /// or returns `None` if the type is not numeric.
-    pub fn numeric_max_val(self, tcx: TyCtxt<'tcx>) -> Option<Const<'tcx>> {
+    pub fn numeric_max_val(self, tcx: TyCtxt<'tcx>) -> Option<ty::Const<'tcx>> {
         let val = match self.kind() {
             ty::Int(_) | ty::Uint(_) => {
                 let (size, signed) = int_size_and_signed(tcx, self);
@@ -704,12 +761,13 @@
             }),
             _ => None,
         };
-        val.map(|v| Const::from_bits(tcx, v, ty::ParamEnv::empty().and(self)))
+
+        val.map(|v| ty::Const::from_bits(tcx, v, ty::ParamEnv::empty().and(self)))
     }
 
     /// Returns the minimum value for the given numeric type (including `char`s)
     /// or returns `None` if the type is not numeric.
-    pub fn numeric_min_val(self, tcx: TyCtxt<'tcx>) -> Option<Const<'tcx>> {
+    pub fn numeric_min_val(self, tcx: TyCtxt<'tcx>) -> Option<ty::Const<'tcx>> {
         let val = match self.kind() {
             ty::Int(_) | ty::Uint(_) => {
                 let (size, signed) = int_size_and_signed(tcx, self);
@@ -723,7 +781,8 @@
             }),
             _ => None,
         };
-        val.map(|v| Const::from_bits(tcx, v, ty::ParamEnv::empty().and(self)))
+
+        val.map(|v| ty::Const::from_bits(tcx, v, ty::ParamEnv::empty().and(self)))
     }
 
     /// Checks whether values of this type `T` are *moved* or *copied*
@@ -927,35 +986,40 @@
     pub fn is_structural_eq_shallow(self, tcx: TyCtxt<'tcx>) -> bool {
         match self.kind() {
             // Look for an impl of both `PartialStructuralEq` and `StructuralEq`.
-            Adt(..) => tcx.has_structural_eq_impls(self),
+            ty::Adt(..) => tcx.has_structural_eq_impls(self),
 
             // Primitive types that satisfy `Eq`.
-            Bool | Char | Int(_) | Uint(_) | Str | Never => true,
+            ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Str | ty::Never => true,
 
             // Composite types that satisfy `Eq` when all of their fields do.
             //
             // Because this function is "shallow", we return `true` for these composites regardless
             // of the type(s) contained within.
-            Ref(..) | Array(..) | Slice(_) | Tuple(..) => true,
+            ty::Ref(..) | ty::Array(..) | ty::Slice(_) | ty::Tuple(..) => true,
 
             // Raw pointers use bitwise comparison.
-            RawPtr(_) | FnPtr(_) => true,
+            ty::RawPtr(_) | ty::FnPtr(_) => true,
 
             // Floating point numbers are not `Eq`.
-            Float(_) => false,
+            ty::Float(_) => false,
 
             // Conservatively return `false` for all others...
 
             // Anonymous function types
-            FnDef(..) | Closure(..) | Dynamic(..) | Generator(..) => false,
+            ty::FnDef(..) | ty::Closure(..) | ty::Dynamic(..) | ty::Generator(..) => false,
 
             // Generic or inferred types
             //
             // FIXME(ecstaticmorse): Maybe we should `bug` here? This should probably only be
             // called for known, fully-monomorphized types.
-            Projection(_) | Opaque(..) | Param(_) | Bound(..) | Placeholder(_) | Infer(_) => false,
+            ty::Projection(_)
+            | ty::Opaque(..)
+            | ty::Param(_)
+            | ty::Bound(..)
+            | ty::Placeholder(_)
+            | ty::Infer(_) => false,
 
-            Foreign(_) | GeneratorWitness(..) | Error(_) => false,
+            ty::Foreign(_) | ty::GeneratorWitness(..) | ty::Error(_) => false,
         }
     }
 
@@ -971,13 +1035,13 @@
     /// - `&'a *const &'b u8 -> *const &'b u8`
     pub fn peel_refs(self) -> Ty<'tcx> {
         let mut ty = self;
-        while let Ref(_, inner_ty, _) = ty.kind() {
+        while let ty::Ref(_, inner_ty, _) = ty.kind() {
             ty = *inner_ty;
         }
         ty
     }
 
-    pub fn outer_exclusive_binder(self) -> DebruijnIndex {
+    pub fn outer_exclusive_binder(self) -> ty::DebruijnIndex {
         self.0.outer_exclusive_binder
     }
 }
@@ -1063,7 +1127,7 @@
         ty::Array(elem_ty, size) => {
             match needs_drop_components(*elem_ty, target_layout) {
                 Ok(v) if v.is_empty() => Ok(v),
-                res => match size.val().try_to_bits(target_layout.pointer_size) {
+                res => match size.kind().try_to_bits(target_layout.pointer_size) {
                     // Arrays of size zero don't need drop, even if their element
                     // type does.
                     Some(0) => Ok(SmallVec::new()),
@@ -1174,8 +1238,8 @@
 /// with their underlying types.
 pub fn normalize_opaque_types<'tcx>(
     tcx: TyCtxt<'tcx>,
-    val: &'tcx List<ty::Predicate<'tcx>>,
-) -> &'tcx List<ty::Predicate<'tcx>> {
+    val: &'tcx ty::List<ty::Predicate<'tcx>>,
+) -> &'tcx ty::List<ty::Predicate<'tcx>> {
     let mut visitor = OpaqueTypeExpander {
         seen_opaque_tys: FxHashSet::default(),
         expanded_cache: FxHashMap::default(),
@@ -1195,6 +1259,12 @@
         .any(|items| items.iter().any(|item| item.has_name(sym::hidden)))
 }
 
+/// Determines whether an item is an intrinsic by Abi.
+pub fn is_intrinsic(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
+    matches!(tcx.fn_sig(def_id).abi(), Abi::RustIntrinsic | Abi::PlatformIntrinsic)
+}
+
 pub fn provide(providers: &mut ty::query::Providers) {
-    *providers = ty::query::Providers { normalize_opaque_types, is_doc_hidden, ..*providers }
+    *providers =
+        ty::query::Providers { normalize_opaque_types, is_doc_hidden, is_intrinsic, ..*providers }
 }
diff --git a/compiler/rustc_middle/src/ty/vtable.rs b/compiler/rustc_middle/src/ty/vtable.rs
index f766cad..04a9fd1 100644
--- a/compiler/rustc_middle/src/ty/vtable.rs
+++ b/compiler/rustc_middle/src/ty/vtable.rs
@@ -36,8 +36,11 @@
     }
 }
 
-pub const COMMON_VTABLE_ENTRIES: &[VtblEntry<'_>] =
-    &[VtblEntry::MetadataDropInPlace, VtblEntry::MetadataSize, VtblEntry::MetadataAlign];
+// Needs to be associated with the `'tcx` lifetime
+impl<'tcx> TyCtxt<'tcx> {
+    pub const COMMON_VTABLE_ENTRIES: &'tcx [VtblEntry<'tcx>] =
+        &[VtblEntry::MetadataDropInPlace, VtblEntry::MetadataSize, VtblEntry::MetadataAlign];
+}
 
 pub const COMMON_VTABLE_ENTRIES_DROPINPLACE: usize = 0;
 pub const COMMON_VTABLE_ENTRIES_SIZE: usize = 1;
@@ -57,7 +60,7 @@
 
         tcx.vtable_entries(trait_ref)
     } else {
-        COMMON_VTABLE_ENTRIES
+        TyCtxt::COMMON_VTABLE_ENTRIES
     };
 
     let layout = tcx
diff --git a/compiler/rustc_middle/src/ty/walk.rs b/compiler/rustc_middle/src/ty/walk.rs
index 09946f0..02fe1f3 100644
--- a/compiler/rustc_middle/src/ty/walk.rs
+++ b/compiler/rustc_middle/src/ty/walk.rs
@@ -190,7 +190,7 @@
         GenericArgKind::Lifetime(_) => {}
         GenericArgKind::Const(parent_ct) => {
             stack.push(parent_ct.ty().into());
-            match parent_ct.val() {
+            match parent_ct.kind() {
                 ty::ConstKind::Infer(_)
                 | ty::ConstKind::Param(_)
                 | ty::ConstKind::Placeholder(_)
diff --git a/compiler/rustc_mir_build/src/build/block.rs b/compiler/rustc_mir_build/src/build/block.rs
index 679043b..a83328c 100644
--- a/compiler/rustc_mir_build/src/build/block.rs
+++ b/compiler/rustc_mir_build/src/build/block.rs
@@ -6,7 +6,7 @@
 use rustc_span::Span;
 
 impl<'a, 'tcx> Builder<'a, 'tcx> {
-    crate fn ast_block(
+    pub(crate) fn ast_block(
         &mut self,
         destination: Place<'tcx>,
         block: BasicBlock,
diff --git a/compiler/rustc_mir_build/src/build/cfg.rs b/compiler/rustc_mir_build/src/build/cfg.rs
index ac92b03..d7b4b1f 100644
--- a/compiler/rustc_mir_build/src/build/cfg.rs
+++ b/compiler/rustc_mir_build/src/build/cfg.rs
@@ -5,33 +5,33 @@
 use rustc_middle::ty::TyCtxt;
 
 impl<'tcx> CFG<'tcx> {
-    crate fn block_data(&self, blk: BasicBlock) -> &BasicBlockData<'tcx> {
+    pub(crate) fn block_data(&self, blk: BasicBlock) -> &BasicBlockData<'tcx> {
         &self.basic_blocks[blk]
     }
 
-    crate fn block_data_mut(&mut self, blk: BasicBlock) -> &mut BasicBlockData<'tcx> {
+    pub(crate) fn block_data_mut(&mut self, blk: BasicBlock) -> &mut BasicBlockData<'tcx> {
         &mut self.basic_blocks[blk]
     }
 
     // llvm.org/PR32488 makes this function use an excess of stack space. Mark
     // it as #[inline(never)] to keep rustc's stack use in check.
     #[inline(never)]
-    crate fn start_new_block(&mut self) -> BasicBlock {
+    pub(crate) fn start_new_block(&mut self) -> BasicBlock {
         self.basic_blocks.push(BasicBlockData::new(None))
     }
 
-    crate fn start_new_cleanup_block(&mut self) -> BasicBlock {
+    pub(crate) fn start_new_cleanup_block(&mut self) -> BasicBlock {
         let bb = self.start_new_block();
         self.block_data_mut(bb).is_cleanup = true;
         bb
     }
 
-    crate fn push(&mut self, block: BasicBlock, statement: Statement<'tcx>) {
+    pub(crate) fn push(&mut self, block: BasicBlock, statement: Statement<'tcx>) {
         debug!("push({:?}, {:?})", block, statement);
         self.block_data_mut(block).statements.push(statement);
     }
 
-    crate fn push_assign(
+    pub(crate) fn push_assign(
         &mut self,
         block: BasicBlock,
         source_info: SourceInfo,
@@ -44,7 +44,7 @@
         );
     }
 
-    crate fn push_assign_constant(
+    pub(crate) fn push_assign_constant(
         &mut self,
         block: BasicBlock,
         source_info: SourceInfo,
@@ -59,7 +59,7 @@
         );
     }
 
-    crate fn push_assign_unit(
+    pub(crate) fn push_assign_unit(
         &mut self,
         block: BasicBlock,
         source_info: SourceInfo,
@@ -78,7 +78,7 @@
         );
     }
 
-    crate fn push_fake_read(
+    pub(crate) fn push_fake_read(
         &mut self,
         block: BasicBlock,
         source_info: SourceInfo,
@@ -90,7 +90,7 @@
         self.push(block, stmt);
     }
 
-    crate fn terminate(
+    pub(crate) fn terminate(
         &mut self,
         block: BasicBlock,
         source_info: SourceInfo,
@@ -107,7 +107,7 @@
     }
 
     /// In the `origin` block, push a `goto -> target` terminator.
-    crate fn goto(&mut self, origin: BasicBlock, source_info: SourceInfo, target: BasicBlock) {
+    pub(crate) fn goto(&mut self, origin: BasicBlock, source_info: SourceInfo, target: BasicBlock) {
         self.terminate(origin, source_info, TerminatorKind::Goto { target })
     }
 }
diff --git a/compiler/rustc_mir_build/src/build/expr/as_constant.rs b/compiler/rustc_mir_build/src/build/expr/as_constant.rs
index 3a6e59d..3d6e50f 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_constant.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_constant.rs
@@ -1,11 +1,11 @@
 //! See docs in build/expr/mod.rs
 
-use crate::build::Builder;
-use crate::thir::constant::parse_float;
+use crate::build::{parse_float_into_constval, Builder};
 use rustc_ast as ast;
 use rustc_hir::def_id::DefId;
-use rustc_middle::mir::interpret::Allocation;
-use rustc_middle::mir::interpret::{ConstValue, LitToConstError, LitToConstInput, Scalar};
+use rustc_middle::mir::interpret::{
+    Allocation, ConstValue, LitToConstError, LitToConstInput, Scalar,
+};
 use rustc_middle::mir::*;
 use rustc_middle::thir::*;
 use rustc_middle::ty::subst::SubstsRef;
@@ -15,11 +15,11 @@
 impl<'a, 'tcx> Builder<'a, 'tcx> {
     /// Compile `expr`, yielding a compile-time constant. Assumes that
     /// `expr` is a valid compile-time constant!
-    crate fn as_constant(&mut self, expr: &Expr<'tcx>) -> Constant<'tcx> {
+    pub(crate) fn as_constant(&mut self, expr: &Expr<'tcx>) -> Constant<'tcx> {
         let create_uneval_from_def_id =
             |tcx: TyCtxt<'tcx>, def_id: DefId, ty: Ty<'tcx>, substs: SubstsRef<'tcx>| {
                 let uneval = ty::Unevaluated::new(ty::WithOptConstParam::unknown(def_id), substs);
-                tcx.mk_const(ty::ConstS { val: ty::ConstKind::Unevaluated(uneval), ty })
+                tcx.mk_const(ty::ConstS { kind: ty::ConstKind::Unevaluated(uneval), ty })
             };
 
         let this = self;
@@ -68,7 +68,7 @@
             }
             ExprKind::ConstParam { param, def_id: _ } => {
                 let const_param =
-                    tcx.mk_const(ty::ConstS { val: ty::ConstKind::Param(param), ty: expr.ty });
+                    tcx.mk_const(ty::ConstS { kind: ty::ConstKind::Param(param), ty: expr.ty });
                 let literal = ConstantKind::Ty(const_param);
 
                 Constant { user_ty: None, span, literal }
@@ -90,7 +90,7 @@
 }
 
 #[instrument(skip(tcx, lit_input))]
-fn lit_to_mir_constant<'tcx>(
+pub(crate) fn lit_to_mir_constant<'tcx>(
     tcx: TyCtxt<'tcx>,
     lit_input: LitToConstInput<'tcx>,
 ) -> Result<ConstantKind<'tcx>, LitToConstError> {
@@ -129,7 +129,7 @@
             trunc(if neg { (*n as i128).overflowing_neg().0 as u128 } else { *n })?
         }
         (ast::LitKind::Float(n, _), ty::Float(fty)) => {
-            parse_float(*n, *fty, neg).ok_or(LitToConstError::Reported)?
+            parse_float_into_constval(*n, *fty, neg).ok_or(LitToConstError::Reported)?
         }
         (ast::LitKind::Bool(b), ty::Bool) => ConstValue::Scalar(Scalar::from_bool(*b)),
         (ast::LitKind::Char(c), ty::Char) => ConstValue::Scalar(Scalar::from_char(*c)),
diff --git a/compiler/rustc_mir_build/src/build/expr/as_operand.rs b/compiler/rustc_mir_build/src/build/expr/as_operand.rs
index 7eca494..e707c37 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_operand.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_operand.rs
@@ -14,7 +14,7 @@
     /// after the current enclosing `ExprKind::Scope` has ended, so
     /// please do *not* return it from functions to avoid bad
     /// miscompiles.
-    crate fn as_local_operand(
+    pub(crate) fn as_local_operand(
         &mut self,
         block: BasicBlock,
         expr: &Expr<'tcx>,
@@ -73,7 +73,7 @@
     /// value to the stack.
     ///
     /// See #68034 for more details.
-    crate fn as_local_call_operand(
+    pub(crate) fn as_local_call_operand(
         &mut self,
         block: BasicBlock,
         expr: &Expr<'tcx>,
@@ -97,7 +97,7 @@
     /// Like `as_local_call_operand`, except that the argument will
     /// not be valid once `scope` ends.
     #[instrument(level = "debug", skip(self, scope))]
-    crate fn as_operand(
+    pub(crate) fn as_operand(
         &mut self,
         mut block: BasicBlock,
         scope: Option<region::Scope>,
@@ -132,7 +132,7 @@
         }
     }
 
-    crate fn as_call_operand(
+    pub(crate) fn as_call_operand(
         &mut self,
         mut block: BasicBlock,
         scope: Option<region::Scope>,
diff --git a/compiler/rustc_mir_build/src/build/expr/as_place.rs b/compiler/rustc_mir_build/src/build/expr/as_place.rs
index fa1bb06..e77f593 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_place.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs
@@ -3,8 +3,8 @@
 use crate::build::expr::category::Category;
 use crate::build::ForGuard::{OutsideGuard, RefWithinGuard};
 use crate::build::{BlockAnd, BlockAndExtension, Builder};
-use rustc_hir::def_id::DefId;
-use rustc_hir::HirId;
+use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_middle::hir::place::Projection as HirProjection;
 use rustc_middle::hir::place::ProjectionKind as HirProjectionKind;
 use rustc_middle::middle::region;
 use rustc_middle::mir::AssertKind::BoundsCheck;
@@ -21,7 +21,7 @@
 
 /// The "outermost" place that holds this value.
 #[derive(Copy, Clone, Debug, PartialEq)]
-crate enum PlaceBase {
+pub(crate) enum PlaceBase {
     /// Denotes the start of a `Place`.
     Local(Local),
 
@@ -56,7 +56,7 @@
     /// figure out that it is captured until all the `Field` projections are applied.
     Upvar {
         /// HirId of the upvar
-        var_hir_id: HirId,
+        var_hir_id: LocalVarId,
         /// DefId of the closure
         closure_def_id: DefId,
         /// The trait closure implements, `Fn`, `FnMut`, `FnOnce`
@@ -71,7 +71,7 @@
 /// This is used internally when building a place for an expression like `a.b.c`. The fields `b`
 /// and `c` can be progressively pushed onto the place builder that is created when converting `a`.
 #[derive(Clone, Debug, PartialEq)]
-crate struct PlaceBuilder<'tcx> {
+pub(crate) struct PlaceBuilder<'tcx> {
     base: PlaceBase,
     projection: Vec<PlaceElem<'tcx>>,
 }
@@ -133,7 +133,7 @@
 ///        ancestor of `foo.x.y`. It's the caller's responsibility to ensure that both projections
 ///        list are being applied to the same root variable.
 fn is_ancestor_or_same_capture(
-    proj_possible_ancestor: &Vec<HirProjectionKind>,
+    proj_possible_ancestor: &[HirProjectionKind],
     proj_capture: &[HirProjectionKind],
 ) -> bool {
     // We want to make sure `is_ancestor_or_same_capture("x.0.0", "x.0")` to return false.
@@ -150,12 +150,12 @@
 /// `ty::MinCaptureList` of the root variable `var_hir_id`.
 fn compute_capture_idx<'tcx>(
     closure_min_captures: &ty::RootVariableMinCaptureList<'tcx>,
-    var_hir_id: HirId,
+    var_hir_id: LocalVarId,
     root_var_idx: usize,
 ) -> usize {
     let mut res = 0;
     for (var_id, capture_list) in closure_min_captures {
-        if *var_id == var_hir_id {
+        if *var_id == var_hir_id.0 {
             res += root_var_idx;
             break;
         } else {
@@ -175,19 +175,19 @@
 /// Returns None, when the ancestor is not found.
 fn find_capture_matching_projections<'a, 'tcx>(
     typeck_results: &'a ty::TypeckResults<'tcx>,
-    var_hir_id: HirId,
+    var_hir_id: LocalVarId,
     closure_def_id: DefId,
     projections: &[PlaceElem<'tcx>],
 ) -> Option<(usize, &'a ty::CapturedPlace<'tcx>)> {
     let closure_min_captures = typeck_results.closure_min_captures.get(&closure_def_id)?;
-    let root_variable_min_captures = closure_min_captures.get(&var_hir_id)?;
+    let root_variable_min_captures = closure_min_captures.get(&var_hir_id.0)?;
 
     let hir_projections = convert_to_hir_projections_and_truncate_for_capture(projections);
 
     // If an ancestor is found, `idx` is the index within the list of captured places
     // for root variable `var_hir_id` and `capture` is the `ty::CapturedPlace` itself.
     let (idx, capture) = root_variable_min_captures.iter().enumerate().find(|(_, capture)| {
-        let possible_ancestor_proj_kinds =
+        let possible_ancestor_proj_kinds: Vec<_> =
             capture.place.projections.iter().map(|proj| proj.kind).collect();
         is_ancestor_or_same_capture(&possible_ancestor_proj_kinds, &hir_projections)
     })?;
@@ -268,22 +268,54 @@
                 ty::UpvarCapture::ByValue => upvar_resolved_place_builder,
             };
 
-            let next_projection = capture.place.projections.len();
-            let mut curr_projections = from_builder.projection;
-
             // We used some of the projections to build the capture itself,
             // now we apply the remaining to the upvar resolved place.
-            upvar_resolved_place_builder
-                .projection
-                .extend(curr_projections.drain(next_projection..));
+            let remaining_projections = strip_prefix(
+                capture.place.base_ty,
+                from_builder.projection,
+                &capture.place.projections,
+            );
+            upvar_resolved_place_builder.projection.extend(remaining_projections);
 
             Ok(upvar_resolved_place_builder)
         }
     }
 }
 
+/// Returns projections remaining after stripping an initial prefix of HIR
+/// projections.
+///
+/// Supports only HIR projection kinds that represent a path that might be
+/// captured by a closure or a generator, i.e., an `Index` or a `Subslice`
+/// projection kinds are unsupported.
+fn strip_prefix<'tcx>(
+    mut base_ty: Ty<'tcx>,
+    projections: Vec<PlaceElem<'tcx>>,
+    prefix_projections: &[HirProjection<'tcx>],
+) -> impl Iterator<Item = PlaceElem<'tcx>> {
+    let mut iter = projections.into_iter();
+    for projection in prefix_projections {
+        match projection.kind {
+            HirProjectionKind::Deref => {
+                assert!(matches!(iter.next(), Some(ProjectionElem::Deref)));
+            }
+            HirProjectionKind::Field(..) => {
+                if base_ty.is_enum() {
+                    assert!(matches!(iter.next(), Some(ProjectionElem::Downcast(..))));
+                }
+                assert!(matches!(iter.next(), Some(ProjectionElem::Field(..))));
+            }
+            HirProjectionKind::Index | HirProjectionKind::Subslice => {
+                bug!("unexpected projection kind: {:?}", projection);
+            }
+        }
+        base_ty = projection.ty;
+    }
+    iter
+}
+
 impl<'tcx> PlaceBuilder<'tcx> {
-    crate fn into_place<'a>(
+    pub(crate) fn into_place<'a>(
         self,
         tcx: TyCtxt<'tcx>,
         typeck_results: &'a ty::TypeckResults<'tcx>,
@@ -314,7 +346,7 @@
     /// not captured. This can happen because the final mir that will be
     /// generated doesn't require a read for this place. Failures will only
     /// happen inside closures.
-    crate fn try_upvars_resolved<'a>(
+    pub(crate) fn try_upvars_resolved<'a>(
         self,
         tcx: TyCtxt<'tcx>,
         typeck_results: &'a ty::TypeckResults<'tcx>,
@@ -322,19 +354,19 @@
         to_upvars_resolved_place_builder(self, tcx, typeck_results)
     }
 
-    crate fn base(&self) -> PlaceBase {
+    pub(crate) fn base(&self) -> PlaceBase {
         self.base
     }
 
-    crate fn field(self, f: Field, ty: Ty<'tcx>) -> Self {
+    pub(crate) fn field(self, f: Field, ty: Ty<'tcx>) -> Self {
         self.project(PlaceElem::Field(f, ty))
     }
 
-    crate fn deref(self) -> Self {
+    pub(crate) fn deref(self) -> Self {
         self.project(PlaceElem::Deref)
     }
 
-    crate fn downcast(self, adt_def: AdtDef<'tcx>, variant_index: VariantIdx) -> Self {
+    pub(crate) fn downcast(self, adt_def: AdtDef<'tcx>, variant_index: VariantIdx) -> Self {
         self.project(PlaceElem::Downcast(Some(adt_def.variant(variant_index).name), variant_index))
     }
 
@@ -342,7 +374,7 @@
         self.project(PlaceElem::Index(index))
     }
 
-    crate fn project(mut self, elem: PlaceElem<'tcx>) -> Self {
+    pub(crate) fn project(mut self, elem: PlaceElem<'tcx>) -> Self {
         self.projection.push(elem);
         self
     }
@@ -373,7 +405,7 @@
     /// Extra care is needed if any user code is allowed to run between calling
     /// this method and using it, as is the case for `match` and index
     /// expressions.
-    crate fn as_place(
+    pub(crate) fn as_place(
         &mut self,
         mut block: BasicBlock,
         expr: &Expr<'tcx>,
@@ -384,7 +416,7 @@
 
     /// This is used when constructing a compound `Place`, so that we can avoid creating
     /// intermediate `Place` values until we know the full set of projections.
-    crate fn as_place_builder(
+    pub(crate) fn as_place_builder(
         &mut self,
         block: BasicBlock,
         expr: &Expr<'tcx>,
@@ -397,7 +429,7 @@
     /// place. The place itself may or may not be mutable:
     /// * If this expr is a place expr like a.b, then we will return that place.
     /// * Otherwise, a temporary is created: in that event, it will be an immutable temporary.
-    crate fn as_read_only_place(
+    pub(crate) fn as_read_only_place(
         &mut self,
         mut block: BasicBlock,
         expr: &Expr<'tcx>,
@@ -438,11 +470,15 @@
                     this.expr_as_place(block, &this.thir[value], mutability, fake_borrow_temps)
                 })
             }
-            ExprKind::Field { lhs, name } => {
-                let place_builder = unpack!(
-                    block =
-                        this.expr_as_place(block, &this.thir[lhs], mutability, fake_borrow_temps,)
-                );
+            ExprKind::Field { lhs, variant_index, name } => {
+                let lhs = &this.thir[lhs];
+                let mut place_builder =
+                    unpack!(block = this.expr_as_place(block, lhs, mutability, fake_borrow_temps,));
+                if let ty::Adt(adt_def, _) = lhs.ty.kind() {
+                    if adt_def.is_enum() {
+                        place_builder = place_builder.downcast(*adt_def, variant_index);
+                    }
+                }
                 block.and(place_builder.field(name, expr.ty))
             }
             ExprKind::Deref { arg } => {
@@ -463,8 +499,7 @@
                 source_info,
             ),
             ExprKind::UpvarRef { closure_def_id, var_hir_id } => {
-                let upvar_id = ty::UpvarId::new(var_hir_id, closure_def_id.expect_local());
-                this.lower_captured_upvar(block, upvar_id)
+                this.lower_captured_upvar(block, closure_def_id.expect_local(), var_hir_id)
             }
 
             ExprKind::VarRef { id } => {
@@ -590,11 +625,11 @@
     fn lower_captured_upvar(
         &mut self,
         block: BasicBlock,
-        upvar_id: ty::UpvarId,
+        closure_expr_id: LocalDefId,
+        var_hir_id: LocalVarId,
     ) -> BlockAnd<PlaceBuilder<'tcx>> {
-        let closure_ty = self
-            .typeck_results
-            .node_type(self.tcx.hir().local_def_id_to_hir_id(upvar_id.closure_expr_id));
+        let closure_ty =
+            self.typeck_results.node_type(self.tcx.hir().local_def_id_to_hir_id(closure_expr_id));
 
         let closure_kind = if let ty::Closure(_, closure_substs) = closure_ty.kind() {
             self.infcx.closure_kind(closure_substs).unwrap()
@@ -604,8 +639,8 @@
         };
 
         block.and(PlaceBuilder::from(PlaceBase::Upvar {
-            var_hir_id: upvar_id.var_path.hir_id,
-            closure_def_id: upvar_id.closure_expr_id.to_def_id(),
+            var_hir_id,
+            closure_def_id: closure_expr_id.to_def_id(),
             closure_kind,
         }))
     }
diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
index d807500..8e87ecd 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
@@ -11,6 +11,7 @@
 use rustc_middle::mir::Place;
 use rustc_middle::mir::*;
 use rustc_middle::thir::*;
+use rustc_middle::ty::cast::CastTy;
 use rustc_middle::ty::{self, Ty, UpvarSubsts};
 use rustc_span::Span;
 
@@ -21,7 +22,7 @@
     /// The operand returned from this function will *not be valid* after
     /// an ExprKind::Scope is passed, so please do *not* return it from
     /// functions to avoid bad miscompiles.
-    crate fn as_local_rvalue(
+    pub(crate) fn as_local_rvalue(
         &mut self,
         block: BasicBlock,
         expr: &Expr<'tcx>,
@@ -31,7 +32,7 @@
     }
 
     /// Compile `expr`, yielding an rvalue.
-    crate fn as_rvalue(
+    pub(crate) fn as_rvalue(
         &mut self,
         mut block: BasicBlock,
         scope: Option<region::Scope>,
@@ -52,11 +53,20 @@
                 })
             }
             ExprKind::Repeat { value, count } => {
-                let value_operand = unpack!(
-                    block =
-                        this.as_operand(block, scope, &this.thir[value], None, NeedsTemporary::No)
-                );
-                block.and(Rvalue::Repeat(value_operand, count))
+                if Some(0) == count.try_eval_usize(this.tcx, this.param_env) {
+                    this.build_zero_repeat(block, value, scope, source_info)
+                } else {
+                    let value_operand = unpack!(
+                        block = this.as_operand(
+                            block,
+                            scope,
+                            &this.thir[value],
+                            None,
+                            NeedsTemporary::No
+                        )
+                    );
+                    block.and(Rvalue::Repeat(value_operand, count))
+                }
             }
             ExprKind::Binary { op, lhs, rhs } => {
                 let lhs = unpack!(
@@ -141,7 +151,8 @@
                     TerminatorKind::Call {
                         func: exchange_malloc,
                         args: vec![Operand::Move(size), Operand::Move(align)],
-                        destination: Some((storage, success)),
+                        destination: storage,
+                        target: Some(success),
                         cleanup: None,
                         from_hir_call: false,
                         fn_span: expr_span,
@@ -178,11 +189,22 @@
                 block.and(Rvalue::Use(Operand::Move(Place::from(result))))
             }
             ExprKind::Cast { source } => {
+                let source = &this.thir[source];
+                let from_ty = CastTy::from_ty(source.ty);
+                let cast_ty = CastTy::from_ty(expr.ty);
+                let cast_kind = match (from_ty, cast_ty) {
+                    (Some(CastTy::Ptr(_) | CastTy::FnPtr), Some(CastTy::Int(_))) => {
+                        CastKind::PointerExposeAddress
+                    }
+                    (Some(CastTy::Int(_)), Some(CastTy::Ptr(_))) => {
+                        CastKind::PointerFromExposedAddress
+                    }
+                    (_, _) => CastKind::Misc,
+                };
                 let source = unpack!(
-                    block =
-                        this.as_operand(block, scope, &this.thir[source], None, NeedsTemporary::No)
+                    block = this.as_operand(block, scope, source, None, NeedsTemporary::No)
                 );
-                block.and(Rvalue::Cast(CastKind::Misc, source, expr.ty))
+                block.and(Rvalue::Cast(cast_kind, source, expr.ty))
             }
             ExprKind::Pointer { cast, source } => {
                 let source = unpack!(
@@ -416,7 +438,7 @@
         }
     }
 
-    crate fn build_binary_op(
+    pub(crate) fn build_binary_op(
         &mut self,
         mut block: BasicBlock,
         op: BinOp,
@@ -515,6 +537,37 @@
         }
     }
 
+    fn build_zero_repeat(
+        &mut self,
+        mut block: BasicBlock,
+        value: ExprId,
+        scope: Option<region::Scope>,
+        outer_source_info: SourceInfo,
+    ) -> BlockAnd<Rvalue<'tcx>> {
+        let this = self;
+        let value = &this.thir[value];
+        let elem_ty = value.ty;
+        if let Some(Category::Constant) = Category::of(&value.kind) {
+            // Repeating a const does nothing
+        } else {
+            // For a non-const, we may need to generate an appropriate `Drop`
+            let value_operand =
+                unpack!(block = this.as_operand(block, scope, value, None, NeedsTemporary::No));
+            if let Operand::Move(to_drop) = value_operand {
+                let success = this.cfg.start_new_block();
+                this.cfg.terminate(
+                    block,
+                    outer_source_info,
+                    TerminatorKind::Drop { place: to_drop, target: success, unwind: None },
+                );
+                this.diverge_from(block);
+                block = success;
+            }
+            this.record_operands_moved(&[value_operand]);
+        }
+        block.and(Rvalue::Aggregate(Box::new(AggregateKind::Array(elem_ty)), Vec::new()))
+    }
+
     fn limit_capture_mutability(
         &mut self,
         upvar_span: Span,
diff --git a/compiler/rustc_mir_build/src/build/expr/as_temp.rs b/compiler/rustc_mir_build/src/build/expr/as_temp.rs
index 6067da2..724b72f 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_temp.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_temp.rs
@@ -10,7 +10,7 @@
 impl<'a, 'tcx> Builder<'a, 'tcx> {
     /// Compile `expr` into a fresh temporary. This is used when building
     /// up rvalues so as to freeze the value that will be consumed.
-    crate fn as_temp(
+    pub(crate) fn as_temp(
         &mut self,
         block: BasicBlock,
         temp_lifetime: Option<region::Scope>,
diff --git a/compiler/rustc_mir_build/src/build/expr/category.rs b/compiler/rustc_mir_build/src/build/expr/category.rs
index bcece39..b1a7064 100644
--- a/compiler/rustc_mir_build/src/build/expr/category.rs
+++ b/compiler/rustc_mir_build/src/build/expr/category.rs
@@ -1,7 +1,7 @@
 use rustc_middle::thir::*;
 
 #[derive(Debug, PartialEq)]
-crate enum Category {
+pub(crate) enum Category {
     // An assignable memory location like `x`, `x.f`, `foo()[3]`, that
     // sort of thing. Something that could appear on the LHS of an `=`
     // sign.
@@ -19,7 +19,7 @@
 // Rvalues fall into different "styles" that will determine which fn
 // is best suited to generate them.
 #[derive(Debug, PartialEq)]
-crate enum RvalueFunc {
+pub(crate) enum RvalueFunc {
     // Best generated by `into`. This is generally exprs that
     // cause branching, like `match`, but also includes calls.
     Into,
@@ -31,7 +31,7 @@
 /// Determines the category for a given expression. Note that scope
 /// and paren expressions have no category.
 impl Category {
-    crate fn of(ek: &ExprKind<'_>) -> Option<Category> {
+    pub(crate) fn of(ek: &ExprKind<'_>) -> Option<Category> {
         match *ek {
             ExprKind::Scope { .. } => None,
 
diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs
index 4399fdf..cffb67e 100644
--- a/compiler/rustc_mir_build/src/build/expr/into.rs
+++ b/compiler/rustc_mir_build/src/build/expr/into.rs
@@ -15,7 +15,7 @@
 impl<'a, 'tcx> Builder<'a, 'tcx> {
     /// Compile `expr`, storing the result into `destination`, which
     /// is assumed to be uninitialized.
-    crate fn expr_into_dest(
+    pub(crate) fn expr_into_dest(
         &mut self,
         destination: Place<'tcx>,
         mut block: BasicBlock,
@@ -63,6 +63,17 @@
                         (if_then_scope, then_source_info),
                         LintLevel::Inherited,
                         |this| {
+                            let source_info = if this.is_let(cond) {
+                                let variable_scope = this.new_source_scope(
+                                    then_expr.span,
+                                    LintLevel::Inherited,
+                                    None,
+                                );
+                                this.source_scope = variable_scope;
+                                SourceInfo { span: then_expr.span, scope: variable_scope }
+                            } else {
+                                this.source_info(then_expr.span)
+                            };
                             let (then_block, else_block) =
                                 this.in_if_then_scope(condition_scope, |this| {
                                     let then_blk = unpack!(this.then_else_break(
@@ -70,8 +81,9 @@
                                         &this.thir[cond],
                                         Some(condition_scope),
                                         condition_scope,
-                                        then_expr.span,
+                                        source_info
                                     ));
+
                                     this.expr_into_dest(destination, then_blk, then_expr)
                                 });
                             then_block.and(else_block)
@@ -97,7 +109,7 @@
             ExprKind::Let { expr, ref pat } => {
                 let scope = this.local_scope();
                 let (true_block, false_block) = this.in_if_then_scope(scope, |this| {
-                    this.lower_let_expr(block, &this.thir[expr], pat, scope, expr_span)
+                    this.lower_let_expr(block, &this.thir[expr], pat, scope, None, expr_span)
                 });
 
                 this.cfg.push_assign_constant(
@@ -255,18 +267,19 @@
                         func: fun,
                         args,
                         cleanup: None,
+                        destination,
                         // The presence or absence of a return edge affects control-flow sensitive
                         // MIR checks and ultimately whether code is accepted or not. We can only
                         // omit the return edge if a return type is visibly uninhabited to a module
                         // that makes the call.
-                        destination: if this.tcx.is_ty_uninhabited_from(
+                        target: if this.tcx.is_ty_uninhabited_from(
                             this.parent_module,
                             expr.ty,
                             this.param_env,
                         ) {
                             None
                         } else {
-                            Some((destination, success))
+                            Some(success)
                         },
                         from_hir_call,
                         fn_span,
@@ -434,11 +447,7 @@
                         }
                         thir::InlineAsmOperand::SymFn { value, span } => {
                             mir::InlineAsmOperand::SymFn {
-                                value: Box::new(Constant {
-                                    span,
-                                    user_ty: None,
-                                    literal: value.into(),
-                                }),
+                                value: Box::new(Constant { span, user_ty: None, literal: value }),
                             }
                         }
                         thir::InlineAsmOperand::SymStatic { def_id } => {
@@ -578,4 +587,12 @@
 
         block_and
     }
+
+    fn is_let(&self, expr: ExprId) -> bool {
+        match self.thir[expr].kind {
+            ExprKind::Let { .. } => true,
+            ExprKind::Scope { value, .. } => self.is_let(value),
+            _ => false,
+        }
+    }
 }
diff --git a/compiler/rustc_mir_build/src/build/expr/mod.rs b/compiler/rustc_mir_build/src/build/expr/mod.rs
index 7be435c..f5ae060 100644
--- a/compiler/rustc_mir_build/src/build/expr/mod.rs
+++ b/compiler/rustc_mir_build/src/build/expr/mod.rs
@@ -60,7 +60,7 @@
 //! basically the point where the "by value" operations are bridged
 //! over to the "by reference" mode (`as_place`).
 
-crate mod as_constant;
+pub(crate) mod as_constant;
 mod as_operand;
 pub mod as_place;
 mod as_rvalue;
diff --git a/compiler/rustc_mir_build/src/build/expr/stmt.rs b/compiler/rustc_mir_build/src/build/expr/stmt.rs
index 46c616f..a7e1331 100644
--- a/compiler/rustc_mir_build/src/build/expr/stmt.rs
+++ b/compiler/rustc_mir_build/src/build/expr/stmt.rs
@@ -10,7 +10,7 @@
     /// (e.g., `some().code(&here());`) then `opt_stmt_span` is the
     /// span of that statement (including its semicolon, if any).
     /// The scope is used if a statement temporary must be dropped.
-    crate fn stmt_expr(
+    pub(crate) fn stmt_expr(
         &mut self,
         mut block: BasicBlock,
         expr: &Expr<'tcx>,
diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs
index fa5ec22..1628f1a 100644
--- a/compiler/rustc_mir_build/src/build/matches/mod.rs
+++ b/compiler/rustc_mir_build/src/build/matches/mod.rs
@@ -14,7 +14,6 @@
     fx::{FxHashSet, FxIndexMap, FxIndexSet},
     stack::ensure_sufficient_stack,
 };
-use rustc_hir::HirId;
 use rustc_index::bit_set::BitSet;
 use rustc_middle::middle::region;
 use rustc_middle::mir::*;
@@ -41,7 +40,7 @@
         expr: &Expr<'tcx>,
         temp_scope_override: Option<region::Scope>,
         break_scope: region::Scope,
-        variable_scope_span: Span,
+        variable_source_info: SourceInfo,
     ) -> BlockAnd<()> {
         let this = self;
         let expr_span = expr.span;
@@ -53,7 +52,7 @@
                     &this.thir[lhs],
                     temp_scope_override,
                     break_scope,
-                    variable_scope_span,
+                    variable_source_info,
                 ));
 
                 let rhs_then_block = unpack!(this.then_else_break(
@@ -61,7 +60,7 @@
                     &this.thir[rhs],
                     temp_scope_override,
                     break_scope,
-                    variable_scope_span,
+                    variable_source_info,
                 ));
 
                 rhs_then_block.unit()
@@ -74,13 +73,18 @@
                         &this.thir[value],
                         temp_scope_override,
                         break_scope,
-                        variable_scope_span,
+                        variable_source_info,
                     )
                 })
             }
-            ExprKind::Let { expr, ref pat } => {
-                this.lower_let_expr(block, &this.thir[expr], pat, break_scope, variable_scope_span)
-            }
+            ExprKind::Let { expr, ref pat } => this.lower_let_expr(
+                block,
+                &this.thir[expr],
+                pat,
+                break_scope,
+                Some(variable_source_info.scope),
+                variable_source_info.span,
+            ),
             _ => {
                 let temp_scope = temp_scope_override.unwrap_or_else(|| this.local_scope());
                 let mutability = Mutability::Mut;
@@ -151,7 +155,8 @@
     ///
     /// * From each pre-binding block to the next pre-binding block.
     /// * From each otherwise block to the next pre-binding block.
-    crate fn match_expr(
+    #[tracing::instrument(level = "debug", skip(self, arms))]
+    pub(crate) fn match_expr(
         &mut self,
         destination: Place<'tcx>,
         span: Span,
@@ -408,7 +413,7 @@
         outer_source_info: SourceInfo,
         candidate: Candidate<'_, 'tcx>,
         guard: Option<&Guard<'tcx>>,
-        fake_borrow_temps: &Vec<(Place<'tcx>, Local)>,
+        fake_borrow_temps: &[(Place<'tcx>, Local)],
         scrutinee_span: Span,
         arm_span: Option<Span>,
         arm_scope: Option<region::Scope>,
@@ -523,8 +528,7 @@
                             },
                         ..
                     },
-                ascription:
-                    thir::Ascription { user_ty: pat_ascription_ty, variance: _, user_ty_span },
+                ascription: thir::Ascription { annotation, variance: _ },
             } => {
                 let place =
                     self.storage_live_binding(block, var, irrefutable_pat.span, OutsideGuard, true);
@@ -535,18 +539,15 @@
                 let cause_let = FakeReadCause::ForLet(None);
                 self.cfg.push_fake_read(block, pattern_source_info, cause_let, place);
 
-                let ty_source_info = self.source_info(user_ty_span);
-                let user_ty = pat_ascription_ty.user_ty(
-                    &mut self.canonical_user_type_annotations,
-                    place.ty(&self.local_decls, self.tcx).ty,
-                    ty_source_info.span,
-                );
+                let ty_source_info = self.source_info(annotation.span);
+
+                let base = self.canonical_user_type_annotations.push(annotation);
                 self.cfg.push(
                     block,
                     Statement {
                         source_info: ty_source_info,
                         kind: StatementKind::AscribeUserType(
-                            Box::new((place, user_ty)),
+                            Box::new((place, UserTypeProjection { base, projs: Vec::new() })),
                             // We always use invariant as the variance here. This is because the
                             // variance field from the ascription refers to the variance to use
                             // when applying the type to the value being matched, but this
@@ -577,7 +578,7 @@
         }
     }
 
-    crate fn place_into_pattern(
+    pub(crate) fn place_into_pattern(
         &mut self,
         block: BasicBlock,
         irrefutable_pat: Pat<'tcx>,
@@ -653,7 +654,7 @@
     /// scope for the bindings in these patterns, if such a scope had to be
     /// created. NOTE: Declaring the bindings should always be done in their
     /// drop scope.
-    crate fn declare_bindings(
+    pub(crate) fn declare_bindings(
         &mut self,
         mut visibility_scope: Option<SourceScope>,
         scope_span: Span,
@@ -690,10 +691,10 @@
         visibility_scope
     }
 
-    crate fn storage_live_binding(
+    pub(crate) fn storage_live_binding(
         &mut self,
         block: BasicBlock,
-        var: HirId,
+        var: LocalVarId,
         span: Span,
         for_guard: ForGuard,
         schedule_drop: bool,
@@ -703,15 +704,20 @@
         self.cfg.push(block, Statement { source_info, kind: StatementKind::StorageLive(local_id) });
         // Altough there is almost always scope for given variable in corner cases
         // like #92893 we might get variable with no scope.
-        if let Some(region_scope) = self.region_scope_tree.var_scope(var.local_id) && schedule_drop{
+        if let Some(region_scope) = self.region_scope_tree.var_scope(var.0.local_id) && schedule_drop{
             self.schedule_drop(span, region_scope, local_id, DropKind::Storage);
         }
         Place::from(local_id)
     }
 
-    crate fn schedule_drop_for_binding(&mut self, var: HirId, span: Span, for_guard: ForGuard) {
+    pub(crate) fn schedule_drop_for_binding(
+        &mut self,
+        var: LocalVarId,
+        span: Span,
+        for_guard: ForGuard,
+    ) {
         let local_id = self.var_local_id(var, for_guard);
-        if let Some(region_scope) = self.region_scope_tree.var_scope(var.local_id) {
+        if let Some(region_scope) = self.region_scope_tree.var_scope(var.0.local_id) {
             self.schedule_drop(span, region_scope, local_id, DropKind::Value);
         }
     }
@@ -728,7 +734,7 @@
             Mutability,
             Symbol,
             BindingMode,
-            HirId,
+            LocalVarId,
             Span,
             Ty<'tcx>,
             UserTypeProjections,
@@ -784,7 +790,7 @@
 
             PatKind::AscribeUserType {
                 ref subpattern,
-                ascription: thir::Ascription { ref user_ty, user_ty_span, variance: _ },
+                ascription: thir::Ascription { ref annotation, variance: _ },
             } => {
                 // This corresponds to something like
                 //
@@ -794,16 +800,13 @@
                 //
                 // Note that the variance doesn't apply here, as we are tracking the effect
                 // of `user_ty` on any bindings contained with subpattern.
-                let annotation = CanonicalUserTypeAnnotation {
-                    span: user_ty_span,
-                    user_ty: user_ty.user_ty,
-                    inferred_ty: subpattern.ty,
-                };
+
                 let projection = UserTypeProjection {
-                    base: self.canonical_user_type_annotations.push(annotation),
+                    base: self.canonical_user_type_annotations.push(annotation.clone()),
                     projs: Vec::new(),
                 };
-                let subpattern_user_ty = pattern_user_ty.push_projection(&projection, user_ty_span);
+                let subpattern_user_ty =
+                    pattern_user_ty.push_projection(&projection, annotation.span);
                 self.visit_primary_bindings(subpattern, subpattern_user_ty, f)
             }
 
@@ -918,7 +921,7 @@
 struct Binding<'tcx> {
     span: Span,
     source: Place<'tcx>,
-    var_id: HirId,
+    var_id: LocalVarId,
     binding_mode: BindingMode,
 }
 
@@ -927,14 +930,13 @@
 /// influence region inference.
 #[derive(Clone, Debug)]
 struct Ascription<'tcx> {
-    span: Span,
     source: Place<'tcx>,
-    user_ty: PatTyProj<'tcx>,
+    annotation: CanonicalUserTypeAnnotation<'tcx>,
     variance: ty::Variance,
 }
 
 #[derive(Clone, Debug)]
-crate struct MatchPair<'pat, 'tcx> {
+pub(crate) struct MatchPair<'pat, 'tcx> {
     // this place...
     place: PlaceBuilder<'tcx>,
 
@@ -966,13 +968,13 @@
         ///
         /// For `bool` we always generate two edges, one for `true` and one for
         /// `false`.
-        options: FxIndexMap<ty::Const<'tcx>, u128>,
+        options: FxIndexMap<ConstantKind<'tcx>, u128>,
     },
 
     /// Test for equality with value, possibly after an unsizing coercion to
     /// `ty`,
     Eq {
-        value: ty::Const<'tcx>,
+        value: ConstantKind<'tcx>,
         // Integer types are handled by `SwitchInt`, and constants with ADT
         // types are converted back into patterns, so this can only be `&str`,
         // `&[T]`, `f32` or `f64`.
@@ -991,7 +993,7 @@
 /// [`Test`] is just the test to perform; it does not include the value
 /// to be tested.
 #[derive(Debug)]
-crate struct Test<'tcx> {
+pub(crate) struct Test<'tcx> {
     span: Span,
     kind: TestKind<'tcx>,
 }
@@ -999,7 +1001,7 @@
 /// `ArmHasGuard` is a wrapper around a boolean flag. It indicates whether
 /// a match arm has a guard expression attached to it.
 #[derive(Copy, Clone, Debug)]
-crate struct ArmHasGuard(crate bool);
+pub(crate) struct ArmHasGuard(pub(crate) bool);
 
 ///////////////////////////////////////////////////////////////////////////
 // Main matching algorithm
@@ -1769,12 +1771,13 @@
 // Pat binding - used for `let` and function parameters as well.
 
 impl<'a, 'tcx> Builder<'a, 'tcx> {
-    crate fn lower_let_expr(
+    pub(crate) fn lower_let_expr(
         &mut self,
         mut block: BasicBlock,
         expr: &Expr<'tcx>,
         pat: &Pat<'tcx>,
         else_target: region::Scope,
+        source_scope: Option<SourceScope>,
         span: Span,
     ) -> BlockAnd<()> {
         let expr_span = expr.span;
@@ -1800,7 +1803,14 @@
         let otherwise_post_guard_block = otherwise_candidate.pre_binding_block.unwrap();
         self.break_for_else(otherwise_post_guard_block, else_target, self.source_info(expr_span));
 
-        self.declare_bindings(None, pat.span.to(span), pat, ArmHasGuard(false), opt_expr_place);
+        self.declare_bindings(
+            source_scope,
+            pat.span.to(span),
+            pat,
+            ArmHasGuard(false),
+            opt_expr_place,
+        );
+
         let post_guard_block = self.bind_pattern(
             self.source_info(pat.span),
             guard_candidate,
@@ -1828,7 +1838,7 @@
         candidate: Candidate<'pat, 'tcx>,
         parent_bindings: &[(Vec<Binding<'tcx>>, Vec<Ascription<'tcx>>)],
         guard: Option<&Guard<'tcx>>,
-        fake_borrows: &Vec<(Place<'tcx>, Local)>,
+        fake_borrows: &[(Place<'tcx>, Local)],
         scrutinee_span: Span,
         arm_span: Option<Span>,
         match_scope: Option<region::Scope>,
@@ -1858,7 +1868,8 @@
             parent_bindings
                 .iter()
                 .flat_map(|(_, ascriptions)| ascriptions)
-                .chain(&candidate.ascriptions),
+                .cloned()
+                .chain(candidate.ascriptions),
         );
 
         // rust-lang/rust#27282: The `autoref` business deserves some
@@ -1971,12 +1982,18 @@
                     Guard::If(e) => {
                         let e = &this.thir[e];
                         guard_span = e.span;
-                        this.then_else_break(block, e, None, match_scope, arm_span)
+                        this.then_else_break(
+                            block,
+                            e,
+                            None,
+                            match_scope,
+                            this.source_info(arm_span),
+                        )
                     }
                     Guard::IfLet(ref pat, scrutinee) => {
                         let s = &this.thir[scrutinee];
                         guard_span = s.span;
-                        this.lower_let_expr(block, s, pat, match_scope, arm_span)
+                        this.lower_let_expr(block, s, pat, match_scope, None, arm_span)
                     }
                 });
 
@@ -2062,32 +2079,24 @@
 
     /// Append `AscribeUserType` statements onto the end of `block`
     /// for each ascription
-    fn ascribe_types<'b>(
+    fn ascribe_types(
         &mut self,
         block: BasicBlock,
-        ascriptions: impl IntoIterator<Item = &'b Ascription<'tcx>>,
-    ) where
-        'tcx: 'b,
-    {
+        ascriptions: impl IntoIterator<Item = Ascription<'tcx>>,
+    ) {
         for ascription in ascriptions {
-            let source_info = self.source_info(ascription.span);
+            let source_info = self.source_info(ascription.annotation.span);
 
-            debug!(
-                "adding user ascription at span {:?} of place {:?} and {:?}",
-                source_info.span, ascription.source, ascription.user_ty,
-            );
-
-            let user_ty = ascription.user_ty.user_ty(
-                &mut self.canonical_user_type_annotations,
-                ascription.source.ty(&self.local_decls, self.tcx).ty,
-                source_info.span,
-            );
+            let base = self.canonical_user_type_annotations.push(ascription.annotation);
             self.cfg.push(
                 block,
                 Statement {
                     source_info,
                     kind: StatementKind::AscribeUserType(
-                        Box::new((ascription.source, user_ty)),
+                        Box::new((
+                            ascription.source,
+                            UserTypeProjection { base, projs: Vec::new() },
+                        )),
                         ascription.variance,
                     ),
                 },
@@ -2193,7 +2202,7 @@
         mutability: Mutability,
         name: Symbol,
         mode: BindingMode,
-        var_id: HirId,
+        var_id: LocalVarId,
         var_ty: Ty<'tcx>,
         user_ty: UserTypeProjections,
         has_guard: ArmHasGuard,
diff --git a/compiler/rustc_mir_build/src/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs
index 7f53d9d..c629890 100644
--- a/compiler/rustc_mir_build/src/build/matches/simplify.rs
+++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs
@@ -152,15 +152,14 @@
         match *match_pair.pattern.kind {
             PatKind::AscribeUserType {
                 ref subpattern,
-                ascription: thir::Ascription { variance, user_ty, user_ty_span },
+                ascription: thir::Ascription { ref annotation, variance },
             } => {
                 // Apply the type ascription to the value at `match_pair.place`, which is the
                 if let Ok(place_resolved) =
                     match_pair.place.clone().try_upvars_resolved(self.tcx, self.typeck_results)
                 {
                     candidate.ascriptions.push(Ascription {
-                        span: user_ty_span,
-                        user_ty,
+                        annotation: annotation.clone(),
                         source: place_resolved.into_place(self.tcx, self.typeck_results),
                         variance,
                     });
@@ -228,17 +227,18 @@
                     _ => (None, 0),
                 };
                 if let Some((min, max, sz)) = range {
-                    if let (Some(lo), Some(hi)) =
-                        (lo.val().try_to_bits(sz), hi.val().try_to_bits(sz))
-                    {
-                        // We want to compare ranges numerically, but the order of the bitwise
-                        // representation of signed integers does not match their numeric order.
-                        // Thus, to correct the ordering, we need to shift the range of signed
-                        // integers to correct the comparison. This is achieved by XORing with a
-                        // bias (see pattern/_match.rs for another pertinent example of this
-                        // pattern).
-                        let (lo, hi) = (lo ^ bias, hi ^ bias);
-                        if lo <= min && (hi > max || hi == max && end == RangeEnd::Included) {
+                    // We want to compare ranges numerically, but the order of the bitwise
+                    // representation of signed integers does not match their numeric order. Thus,
+                    // to correct the ordering, we need to shift the range of signed integers to
+                    // correct the comparison. This is achieved by XORing with a bias (see
+                    // pattern/_match.rs for another pertinent example of this pattern).
+                    //
+                    // Also, for performance, it's important to only do the second `try_to_bits` if
+                    // necessary.
+                    let lo = lo.try_to_bits(sz).unwrap() ^ bias;
+                    if lo <= min {
+                        let hi = hi.try_to_bits(sz).unwrap() ^ bias;
+                        if hi > max || hi == max && end == RangeEnd::Included {
                             // Irrefutable pattern match.
                             return Ok(());
                         }
diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs
index d7993ce..598da80 100644
--- a/compiler/rustc_mir_build/src/build/matches/test.rs
+++ b/compiler/rustc_mir_build/src/build/matches/test.rs
@@ -86,7 +86,7 @@
         test_place: &PlaceBuilder<'tcx>,
         candidate: &Candidate<'pat, 'tcx>,
         switch_ty: Ty<'tcx>,
-        options: &mut FxIndexMap<ty::Const<'tcx>, u128>,
+        options: &mut FxIndexMap<ConstantKind<'tcx>, u128>,
     ) -> bool {
         let Some(match_pair) = candidate.match_pairs.iter().find(|mp| mp.place == *test_place) else {
             return false;
@@ -264,7 +264,7 @@
                     );
                 } else if let [success, fail] = *make_target_blocks(self) {
                     assert_eq!(value.ty(), ty);
-                    let expect = self.literal_operand(test.span, value.into());
+                    let expect = self.literal_operand(test.span, value);
                     let val = Operand::Copy(place);
                     self.compare(block, success, fail, source_info, BinOp::Eq, expect, val);
                 } else {
@@ -277,8 +277,8 @@
                 let target_blocks = make_target_blocks(self);
 
                 // Test `val` by computing `lo <= val && val <= hi`, using primitive comparisons.
-                let lo = self.literal_operand(test.span, lo.into());
-                let hi = self.literal_operand(test.span, hi.into());
+                let lo = self.literal_operand(test.span, lo);
+                let hi = self.literal_operand(test.span, hi);
                 let val = Operand::Copy(place);
 
                 let [success, fail] = *target_blocks else {
@@ -366,11 +366,11 @@
         block: BasicBlock,
         make_target_blocks: impl FnOnce(&mut Self) -> Vec<BasicBlock>,
         source_info: SourceInfo,
-        value: ty::Const<'tcx>,
+        value: ConstantKind<'tcx>,
         place: Place<'tcx>,
         mut ty: Ty<'tcx>,
     ) {
-        let mut expect = self.literal_operand(source_info.span, value.into());
+        let mut expect = self.literal_operand(source_info.span, value);
         let mut val = Operand::Copy(place);
 
         // If we're using `b"..."` as a pattern, we need to insert an
@@ -444,7 +444,8 @@
                     literal: method,
                 })),
                 args: vec![val, expect],
-                destination: Some((eq_result, eq_block)),
+                destination: eq_result,
+                target: Some(eq_block),
                 cleanup: None,
                 from_hir_call: false,
                 fn_span: source_info.span,
@@ -631,39 +632,30 @@
             }
 
             (&TestKind::Range(test), &PatKind::Range(pat)) => {
+                use std::cmp::Ordering::*;
+
                 if test == pat {
                     self.candidate_without_match_pair(match_pair_index, candidate);
                     return Some(0);
                 }
 
-                let no_overlap = (|| {
-                    use rustc_hir::RangeEnd::*;
-                    use std::cmp::Ordering::*;
-
-                    let tcx = self.tcx;
-
-                    let test_ty = test.lo.ty();
-                    let lo = compare_const_vals(tcx, test.lo, pat.hi, self.param_env, test_ty)?;
-                    let hi = compare_const_vals(tcx, test.hi, pat.lo, self.param_env, test_ty)?;
-
-                    match (test.end, pat.end, lo, hi) {
-                        // pat < test
-                        (_, _, Greater, _) |
-                        (_, Excluded, Equal, _) |
-                        // pat > test
-                        (_, _, _, Less) |
-                        (Excluded, _, _, Equal) => Some(true),
-                        _ => Some(false),
-                    }
-                })();
-
-                if let Some(true) = no_overlap {
-                    // Testing range does not overlap with pattern range,
-                    // so the pattern can be matched only if this test fails.
+                // For performance, it's important to only do the second
+                // `compare_const_vals` if necessary.
+                let no_overlap = if matches!(
+                    (compare_const_vals(self.tcx, test.hi, pat.lo, self.param_env)?, test.end),
+                    (Less, _) | (Equal, RangeEnd::Excluded) // test < pat
+                ) || matches!(
+                    (compare_const_vals(self.tcx, test.lo, pat.hi, self.param_env)?, pat.end),
+                    (Greater, _) | (Equal, RangeEnd::Excluded) // test > pat
+                ) {
                     Some(1)
                 } else {
                     None
-                }
+                };
+
+                // If the testing range does not overlap with pattern range,
+                // the pattern can be matched only if this test fails.
+                no_overlap
             }
 
             (&TestKind::Range(range), &PatKind::Constant { value }) => {
@@ -760,24 +752,28 @@
         span_bug!(match_pair.pattern.span, "simplifyable pattern found: {:?}", match_pair.pattern)
     }
 
-    fn const_range_contains(&self, range: PatRange<'tcx>, value: ty::Const<'tcx>) -> Option<bool> {
+    fn const_range_contains(
+        &self,
+        range: PatRange<'tcx>,
+        value: ConstantKind<'tcx>,
+    ) -> Option<bool> {
         use std::cmp::Ordering::*;
 
-        let tcx = self.tcx;
-
-        let a = compare_const_vals(tcx, range.lo, value, self.param_env, range.lo.ty())?;
-        let b = compare_const_vals(tcx, value, range.hi, self.param_env, range.lo.ty())?;
-
-        match (b, range.end) {
-            (Less, _) | (Equal, RangeEnd::Included) if a != Greater => Some(true),
-            _ => Some(false),
-        }
+        // For performance, it's important to only do the second
+        // `compare_const_vals` if necessary.
+        Some(
+            matches!(compare_const_vals(self.tcx, range.lo, value, self.param_env)?, Less | Equal)
+                && matches!(
+                    (compare_const_vals(self.tcx, value, range.hi, self.param_env)?, range.end),
+                    (Less, _) | (Equal, RangeEnd::Included)
+                ),
+        )
     }
 
     fn values_not_contained_in_range(
         &self,
         range: PatRange<'tcx>,
-        options: &FxIndexMap<ty::Const<'tcx>, u128>,
+        options: &FxIndexMap<ConstantKind<'tcx>, u128>,
     ) -> Option<bool> {
         for &val in options.keys() {
             if self.const_range_contains(range, val)? {
diff --git a/compiler/rustc_mir_build/src/build/matches/util.rs b/compiler/rustc_mir_build/src/build/matches/util.rs
index 88dd76e..9a1e98d 100644
--- a/compiler/rustc_mir_build/src/build/matches/util.rs
+++ b/compiler/rustc_mir_build/src/build/matches/util.rs
@@ -8,7 +8,7 @@
 use std::convert::TryInto;
 
 impl<'a, 'tcx> Builder<'a, 'tcx> {
-    crate fn field_match_pairs<'pat>(
+    pub(crate) fn field_match_pairs<'pat>(
         &mut self,
         place: PlaceBuilder<'tcx>,
         subpatterns: &'pat [FieldPat<'tcx>],
@@ -22,7 +22,7 @@
             .collect()
     }
 
-    crate fn prefix_slice_suffix<'pat>(
+    pub(crate) fn prefix_slice_suffix<'pat>(
         &mut self,
         match_pairs: &mut SmallVec<[MatchPair<'pat, 'tcx>; 1]>,
         place: &PlaceBuilder<'tcx>,
@@ -79,7 +79,7 @@
     /// Creates a false edge to `imaginary_target` and a real edge to
     /// real_target. If `imaginary_target` is none, or is the same as the real
     /// target, a Goto is generated instead to simplify the generated MIR.
-    crate fn false_edges(
+    pub(crate) fn false_edges(
         &mut self,
         from_block: BasicBlock,
         real_target: BasicBlock,
@@ -100,7 +100,10 @@
 }
 
 impl<'pat, 'tcx> MatchPair<'pat, 'tcx> {
-    crate fn new(place: PlaceBuilder<'tcx>, pattern: &'pat Pat<'tcx>) -> MatchPair<'pat, 'tcx> {
+    pub(crate) fn new(
+        place: PlaceBuilder<'tcx>,
+        pattern: &'pat Pat<'tcx>,
+    ) -> MatchPair<'pat, 'tcx> {
         MatchPair { place, pattern }
     }
 }
diff --git a/compiler/rustc_mir_build/src/build/misc.rs b/compiler/rustc_mir_build/src/build/misc.rs
index 84762d6..86f466f 100644
--- a/compiler/rustc_mir_build/src/build/misc.rs
+++ b/compiler/rustc_mir_build/src/build/misc.rs
@@ -3,7 +3,6 @@
 
 use crate::build::Builder;
 
-use rustc_middle::mir;
 use rustc_middle::mir::*;
 use rustc_middle::ty::{self, Ty};
 use rustc_span::{Span, DUMMY_SP};
@@ -15,7 +14,7 @@
     ///
     /// N.B., **No cleanup is scheduled for this temporary.** You should
     /// call `schedule_drop` once the temporary is initialized.
-    crate fn temp(&mut self, ty: Ty<'tcx>, span: Span) -> Place<'tcx> {
+    pub(crate) fn temp(&mut self, ty: Ty<'tcx>, span: Span) -> Place<'tcx> {
         // Mark this local as internal to avoid temporaries with types not present in the
         // user's code resulting in ICEs from the generator transform.
         let temp = self.local_decls.push(LocalDecl::new(ty, span).internal());
@@ -26,10 +25,10 @@
 
     /// Convenience function for creating a literal operand, one
     /// without any user type annotation.
-    crate fn literal_operand(
+    pub(crate) fn literal_operand(
         &mut self,
         span: Span,
-        literal: mir::ConstantKind<'tcx>,
+        literal: ConstantKind<'tcx>,
     ) -> Operand<'tcx> {
         let constant = Box::new(Constant { span, user_ty: None, literal });
         Operand::Constant(constant)
@@ -37,13 +36,13 @@
 
     // Returns a zero literal operand for the appropriate type, works for
     // bool, char and integers.
-    crate fn zero_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> {
+    pub(crate) fn zero_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> {
         let literal = ConstantKind::from_bits(self.tcx, 0, ty::ParamEnv::empty().and(ty));
 
         self.literal_operand(span, literal)
     }
 
-    crate fn push_usize(
+    pub(crate) fn push_usize(
         &mut self,
         block: BasicBlock,
         source_info: SourceInfo,
@@ -64,7 +63,7 @@
         temp
     }
 
-    crate fn consume_by_copy_or_move(&self, place: Place<'tcx>) -> Operand<'tcx> {
+    pub(crate) fn consume_by_copy_or_move(&self, place: Place<'tcx>) -> Operand<'tcx> {
         let tcx = self.tcx;
         let ty = place.ty(&self.local_decls, tcx).ty;
         if !self.infcx.type_is_copy_modulo_regions(self.param_env, ty, DUMMY_SP) {
diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs
index a9c8943..e239981 100644
--- a/compiler/rustc_mir_build/src/build/mod.rs
+++ b/compiler/rustc_mir_build/src/build/mod.rs
@@ -1,27 +1,34 @@
 use crate::build;
+pub(crate) use crate::build::expr::as_constant::lit_to_mir_constant;
 use crate::build::expr::as_place::PlaceBuilder;
 use crate::build::scope::DropKind;
 use crate::thir::pattern::pat_from_hir;
+use rustc_apfloat::ieee::{Double, Single};
+use rustc_apfloat::Float;
+use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::ErrorGuaranteed;
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::lang_items::LangItem;
-use rustc_hir::{GeneratorKind, HirIdMap, Node};
+use rustc_hir::{GeneratorKind, Node};
 use rustc_index::vec::{Idx, IndexVec};
 use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
 use rustc_middle::hir::place::PlaceBase as HirPlaceBase;
 use rustc_middle::middle::region;
+use rustc_middle::mir::interpret::ConstValue;
+use rustc_middle::mir::interpret::Scalar;
 use rustc_middle::mir::*;
-use rustc_middle::thir::{BindingMode, Expr, ExprId, LintLevel, PatKind, Thir};
+use rustc_middle::thir::{BindingMode, Expr, ExprId, LintLevel, LocalVarId, PatKind, Thir};
 use rustc_middle::ty::subst::Subst;
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeckResults};
 use rustc_span::symbol::sym;
 use rustc_span::Span;
+use rustc_span::Symbol;
 use rustc_target::spec::abi::Abi;
 
 use super::lints;
 
-crate fn mir_built<'tcx>(
+pub(crate) fn mir_built<'tcx>(
     tcx: TyCtxt<'tcx>,
     def: ty::WithOptConstParam<LocalDefId>,
 ) -> &'tcx rustc_data_structures::steal::Steal<Body<'tcx>> {
@@ -61,8 +68,8 @@
 
     // Figure out what primary body this item has.
     let (body_id, return_ty_span, span_with_body) = match tcx.hir().get(id) {
-        Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(_, decl, body_id, _, _), .. }) => {
-            (*body_id, decl.output.span(), None)
+        Node::Expr(hir::Expr { kind: hir::ExprKind::Closure { fn_decl, body, .. }, .. }) => {
+            (*body, fn_decl.output.span(), None)
         }
         Node::Item(hir::Item {
             kind: hir::ItemKind::Fn(hir::FnSig { decl, .. }, _, body_id),
@@ -389,7 +396,7 @@
 
     /// Maps `HirId`s of variable bindings to the `Local`s created for them.
     /// (A match binding can have two locals; the 2nd is for the arm's guard.)
-    var_indices: HirIdMap<LocalsForNode>,
+    var_indices: FxHashMap<LocalVarId, LocalsForNode>,
     local_decls: IndexVec<Local, LocalDecl<'tcx>>,
     canonical_user_type_annotations: ty::CanonicalUserTypeAnnotations<'tcx>,
     upvar_mutbls: Vec<Mutability>,
@@ -399,11 +406,11 @@
 }
 
 impl<'a, 'tcx> Builder<'a, 'tcx> {
-    fn is_bound_var_in_guard(&self, id: hir::HirId) -> bool {
+    fn is_bound_var_in_guard(&self, id: LocalVarId) -> bool {
         self.guard_context.iter().any(|frame| frame.locals.iter().any(|local| local.id == id))
     }
 
-    fn var_local_id(&self, id: hir::HirId, for_guard: ForGuard) -> Local {
+    fn var_local_id(&self, id: LocalVarId, for_guard: ForGuard) -> Local {
         self.var_indices[&id].local_id(for_guard)
     }
 }
@@ -487,11 +494,11 @@
 
 #[derive(Debug)]
 struct GuardFrameLocal {
-    id: hir::HirId,
+    id: LocalVarId,
 }
 
 impl GuardFrameLocal {
-    fn new(id: hir::HirId, _binding_mode: BindingMode) -> Self {
+    fn new(id: LocalVarId, _binding_mode: BindingMode) -> Self {
         GuardFrameLocal { id }
     }
 }
@@ -1080,6 +1087,70 @@
     }
 }
 
+fn parse_float_into_constval<'tcx>(
+    num: Symbol,
+    float_ty: ty::FloatTy,
+    neg: bool,
+) -> Option<ConstValue<'tcx>> {
+    parse_float_into_scalar(num, float_ty, neg).map(ConstValue::Scalar)
+}
+
+pub(crate) fn parse_float_into_scalar(
+    num: Symbol,
+    float_ty: ty::FloatTy,
+    neg: bool,
+) -> Option<Scalar> {
+    let num = num.as_str();
+    match float_ty {
+        ty::FloatTy::F32 => {
+            let Ok(rust_f) = num.parse::<f32>() else { return None };
+            let mut f = num.parse::<Single>().unwrap_or_else(|e| {
+                panic!("apfloat::ieee::Single failed to parse `{}`: {:?}", num, e)
+            });
+
+            assert!(
+                u128::from(rust_f.to_bits()) == f.to_bits(),
+                "apfloat::ieee::Single gave different result for `{}`: \
+                 {}({:#x}) vs Rust's {}({:#x})",
+                rust_f,
+                f,
+                f.to_bits(),
+                Single::from_bits(rust_f.to_bits().into()),
+                rust_f.to_bits()
+            );
+
+            if neg {
+                f = -f;
+            }
+
+            Some(Scalar::from_f32(f))
+        }
+        ty::FloatTy::F64 => {
+            let Ok(rust_f) = num.parse::<f64>() else { return None };
+            let mut f = num.parse::<Double>().unwrap_or_else(|e| {
+                panic!("apfloat::ieee::Double failed to parse `{}`: {:?}", num, e)
+            });
+
+            assert!(
+                u128::from(rust_f.to_bits()) == f.to_bits(),
+                "apfloat::ieee::Double gave different result for `{}`: \
+                 {}({:#x}) vs Rust's {}({:#x})",
+                rust_f,
+                f,
+                f.to_bits(),
+                Double::from_bits(rust_f.to_bits().into()),
+                rust_f.to_bits()
+            );
+
+            if neg {
+                f = -f;
+            }
+
+            Some(Scalar::from_f64(f))
+        }
+    }
+}
+
 ///////////////////////////////////////////////////////////////////////////
 // Builder methods are broken up into modules, depending on what kind
 // of thing is being lowered. Note that they use the `unpack` macro
diff --git a/compiler/rustc_mir_build/src/build/scope.rs b/compiler/rustc_mir_build/src/build/scope.rs
index 465bd62..b9fd8c5 100644
--- a/compiler/rustc_mir_build/src/build/scope.rs
+++ b/compiler/rustc_mir_build/src/build/scope.rs
@@ -177,7 +177,7 @@
 
 /// The target of an expression that breaks out of a scope
 #[derive(Clone, Copy, Debug)]
-crate enum BreakableTarget {
+pub(crate) enum BreakableTarget {
     Continue(region::Scope),
     Break(region::Scope),
     Return,
@@ -445,7 +445,7 @@
     // ==========================
     //  Start a breakable scope, which tracks where `continue`, `break` and
     //  `return` should branch to.
-    crate fn in_breakable_scope<F>(
+    pub(crate) fn in_breakable_scope<F>(
         &mut self,
         loop_block: Option<BasicBlock>,
         break_destination: Place<'tcx>,
@@ -507,7 +507,7 @@
     /// - We don't need to keep a stack of scopes in the `Builder` because the
     ///   'else' paths will only leave the innermost scope.
     /// - This is also used for match guards.
-    crate fn in_if_then_scope<F>(
+    pub(crate) fn in_if_then_scope<F>(
         &mut self,
         region_scope: region::Scope,
         f: F,
@@ -530,7 +530,7 @@
         (then_block, else_block)
     }
 
-    crate fn in_opt_scope<F, R>(
+    pub(crate) fn in_opt_scope<F, R>(
         &mut self,
         opt_scope: Option<(region::Scope, SourceInfo)>,
         f: F,
@@ -553,7 +553,7 @@
 
     /// Convenience wrapper that pushes a scope and then executes `f`
     /// to build its contents, popping the scope afterwards.
-    crate fn in_scope<F, R>(
+    pub(crate) fn in_scope<F, R>(
         &mut self,
         region_scope: (region::Scope, SourceInfo),
         lint_level: LintLevel,
@@ -597,14 +597,14 @@
     /// scope and call `pop_scope` afterwards. Note that these two
     /// calls must be paired; using `in_scope` as a convenience
     /// wrapper maybe preferable.
-    crate fn push_scope(&mut self, region_scope: (region::Scope, SourceInfo)) {
+    pub(crate) fn push_scope(&mut self, region_scope: (region::Scope, SourceInfo)) {
         self.scopes.push_scope(region_scope, self.source_scope);
     }
 
     /// Pops a scope, which should have region scope `region_scope`,
     /// adding any drops onto the end of `block` that are needed.
     /// This must match 1-to-1 with `push_scope`.
-    crate fn pop_scope(
+    pub(crate) fn pop_scope(
         &mut self,
         region_scope: (region::Scope, SourceInfo),
         mut block: BasicBlock,
@@ -619,7 +619,7 @@
     }
 
     /// Sets up the drops for breaking from `block` to `target`.
-    crate fn break_scope(
+    pub(crate) fn break_scope(
         &mut self,
         mut block: BasicBlock,
         value: Option<&Expr<'tcx>>,
@@ -698,7 +698,7 @@
         self.cfg.start_new_block().unit()
     }
 
-    crate fn break_for_else(
+    pub(crate) fn break_for_else(
         &mut self,
         block: BasicBlock,
         target: region::Scope,
@@ -756,7 +756,7 @@
     }
 
     /// Creates a new source scope, nested in the current one.
-    crate fn new_source_scope(
+    pub(crate) fn new_source_scope(
         &mut self,
         span: Span,
         lint_level: LintLevel,
@@ -791,7 +791,7 @@
     }
 
     /// Given a span and the current source scope, make a SourceInfo.
-    crate fn source_info(&self, span: Span) -> SourceInfo {
+    pub(crate) fn source_info(&self, span: Span) -> SourceInfo {
         SourceInfo { span, scope: self.source_scope }
     }
 
@@ -816,13 +816,13 @@
     /// We would allocate the box but then free it on the unwinding
     /// path; we would also emit a free on the 'success' path from
     /// panic, but that will turn out to be removed as dead-code.
-    crate fn local_scope(&self) -> region::Scope {
+    pub(crate) fn local_scope(&self) -> region::Scope {
         self.scopes.topmost()
     }
 
     // Scheduling drops
     // ================
-    crate fn schedule_drop_storage_and_value(
+    pub(crate) fn schedule_drop_storage_and_value(
         &mut self,
         span: Span,
         region_scope: region::Scope,
@@ -836,7 +836,7 @@
     ///
     /// When called with `DropKind::Storage`, `place` shouldn't be the return
     /// place, or a function parameter.
-    crate fn schedule_drop(
+    pub(crate) fn schedule_drop(
         &mut self,
         span: Span,
         region_scope: region::Scope,
@@ -969,7 +969,7 @@
     /// spurious borrow-check errors -- the problem, ironically, is
     /// not the `DROP(_X)` itself, but the (spurious) unwind pathways
     /// that it creates. See #64391 for an example.
-    crate fn record_operands_moved(&mut self, operands: &[Operand<'tcx>]) {
+    pub(crate) fn record_operands_moved(&mut self, operands: &[Operand<'tcx>]) {
         let local_scope = self.local_scope();
         let scope = self.scopes.scopes.last_mut().unwrap();
 
@@ -1026,12 +1026,13 @@
     ///
     /// This path terminates in Resume. The path isn't created until after all
     /// of the non-unwind paths in this item have been lowered.
-    crate fn diverge_from(&mut self, start: BasicBlock) {
+    pub(crate) fn diverge_from(&mut self, start: BasicBlock) {
         debug_assert!(
             matches!(
                 self.cfg.block_data(start).terminator().kind,
                 TerminatorKind::Assert { .. }
                     | TerminatorKind::Call { .. }
+                    | TerminatorKind::Drop { .. }
                     | TerminatorKind::DropAndReplace { .. }
                     | TerminatorKind::FalseUnwind { .. }
                     | TerminatorKind::InlineAsm { .. }
@@ -1048,7 +1049,7 @@
     /// [TerminatorKind::Yield].
     ///
     /// This path terminates in GeneratorDrop.
-    crate fn generator_drop_cleanup(&mut self, yield_block: BasicBlock) {
+    pub(crate) fn generator_drop_cleanup(&mut self, yield_block: BasicBlock) {
         debug_assert!(
             matches!(
                 self.cfg.block_data(yield_block).terminator().kind,
@@ -1078,7 +1079,7 @@
     }
 
     /// Utility function for *non*-scope code to build their own drops
-    crate fn build_drop_and_replace(
+    pub(crate) fn build_drop_and_replace(
         &mut self,
         block: BasicBlock,
         span: Span,
@@ -1101,7 +1102,7 @@
     /// Creates an `Assert` terminator and return the success block.
     /// If the boolean condition operand is not the expected value,
     /// a runtime panic will be caused with the given message.
-    crate fn assert(
+    pub(crate) fn assert(
         &mut self,
         block: BasicBlock,
         cond: Operand<'tcx>,
@@ -1126,7 +1127,7 @@
     ///
     /// This is only needed for `match` arm scopes, because they have one
     /// entrance per pattern, but only one exit.
-    crate fn clear_top_scope(&mut self, region_scope: region::Scope) {
+    pub(crate) fn clear_top_scope(&mut self, region_scope: region::Scope) {
         let top_scope = self.scopes.scopes.last_mut().unwrap();
 
         assert_eq!(top_scope.region_scope, region_scope);
@@ -1262,7 +1263,7 @@
     }
 
     /// Build the unwind and generator drop trees.
-    crate fn build_drop_trees(&mut self) {
+    pub(crate) fn build_drop_trees(&mut self) {
         if self.generator_kind.is_some() {
             self.build_generator_drop_trees();
         } else {
diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs
index 6c14f20..94b2722 100644
--- a/compiler/rustc_mir_build/src/check_unsafety.rs
+++ b/compiler/rustc_mir_build/src/check_unsafety.rs
@@ -678,7 +678,7 @@
     visitor.visit_expr(&thir[expr]);
 }
 
-crate fn thir_check_unsafety<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) {
+pub(crate) fn thir_check_unsafety<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) {
     if let Some(def) = ty::WithOptConstParam::try_lookup(def_id, tcx) {
         tcx.thir_check_unsafety_for_const_arg(def)
     } else {
@@ -686,7 +686,7 @@
     }
 }
 
-crate fn thir_check_unsafety_for_const_arg<'tcx>(
+pub(crate) fn thir_check_unsafety_for_const_arg<'tcx>(
     tcx: TyCtxt<'tcx>,
     (did, param_did): (LocalDefId, DefId),
 ) {
diff --git a/compiler/rustc_mir_build/src/lib.rs b/compiler/rustc_mir_build/src/lib.rs
index 4ffee59..11cd2a9a 100644
--- a/compiler/rustc_mir_build/src/lib.rs
+++ b/compiler/rustc_mir_build/src/lib.rs
@@ -4,7 +4,6 @@
 #![allow(rustc::potential_query_instability)]
 #![feature(box_patterns)]
 #![feature(control_flow_enum)]
-#![feature(crate_visibility_modifier)]
 #![feature(if_let_guard)]
 #![feature(let_chains)]
 #![feature(let_else)]
@@ -27,6 +26,7 @@
 pub fn provide(providers: &mut Providers) {
     providers.check_match = thir::pattern::check_match;
     providers.lit_to_const = thir::constant::lit_to_const;
+    providers.lit_to_mir_constant = build::lit_to_mir_constant;
     providers.mir_built = build::mir_built;
     providers.thir_check_unsafety = check_unsafety::thir_check_unsafety;
     providers.thir_check_unsafety_for_const_arg = check_unsafety::thir_check_unsafety_for_const_arg;
diff --git a/compiler/rustc_mir_build/src/lints.rs b/compiler/rustc_mir_build/src/lints.rs
index bccff37..5470cc1 100644
--- a/compiler/rustc_mir_build/src/lints.rs
+++ b/compiler/rustc_mir_build/src/lints.rs
@@ -9,7 +9,7 @@
 use rustc_span::Span;
 use std::ops::ControlFlow;
 
-crate fn check<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
+pub(crate) fn check<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
     let def_id = body.source.def_id().expect_local();
 
     if let Some(fn_kind) = tcx.hir().get_by_def_id(def_id).fn_kind() {
diff --git a/compiler/rustc_mir_build/src/thir/constant.rs b/compiler/rustc_mir_build/src/thir/constant.rs
index 30d7fdb..a7e4403 100644
--- a/compiler/rustc_mir_build/src/thir/constant.rs
+++ b/compiler/rustc_mir_build/src/thir/constant.rs
@@ -1,14 +1,8 @@
-use rustc_apfloat::Float;
 use rustc_ast as ast;
-use rustc_middle::mir::interpret::{
-    Allocation, ConstValue, LitToConstError, LitToConstInput, Scalar,
-};
-use rustc_middle::ty::{self, ParamEnv, TyCtxt};
-use rustc_span::symbol::Symbol;
-use rustc_target::abi::Size;
+use rustc_middle::mir::interpret::{LitToConstError, LitToConstInput};
+use rustc_middle::ty::{self, ParamEnv, ScalarInt, TyCtxt};
 
-// FIXME Once valtrees are available, get rid of this function and the query
-crate fn lit_to_const<'tcx>(
+pub(crate) fn lit_to_const<'tcx>(
     tcx: TyCtxt<'tcx>,
     lit_input: LitToConstInput<'tcx>,
 ) -> Result<ty::Const<'tcx>, LitToConstError> {
@@ -20,94 +14,39 @@
         trace!("trunc {} with size {} and shift {}", n, width.bits(), 128 - width.bits());
         let result = width.truncate(n);
         trace!("trunc result: {}", result);
-        Ok(ConstValue::Scalar(Scalar::from_uint(result, width)))
+
+        Ok(ScalarInt::try_from_uint(result, width)
+            .unwrap_or_else(|| bug!("expected to create ScalarInt from uint {:?}", result)))
     };
 
-    let lit = match (lit, &ty.kind()) {
+    let valtree = match (lit, &ty.kind()) {
         (ast::LitKind::Str(s, _), ty::Ref(_, inner_ty, _)) if inner_ty.is_str() => {
-            let s = s.as_str();
-            let allocation = Allocation::from_bytes_byte_aligned_immutable(s.as_bytes());
-            let allocation = tcx.intern_const_alloc(allocation);
-            ConstValue::Slice { data: allocation, start: 0, end: s.len() }
+            let str_bytes = s.as_str().as_bytes();
+            ty::ValTree::from_raw_bytes(tcx, str_bytes)
         }
         (ast::LitKind::ByteStr(data), ty::Ref(_, inner_ty, _))
             if matches!(inner_ty.kind(), ty::Slice(_)) =>
         {
-            let allocation = Allocation::from_bytes_byte_aligned_immutable(data as &[u8]);
-            let allocation = tcx.intern_const_alloc(allocation);
-            ConstValue::Slice { data: allocation, start: 0, end: data.len() }
+            let bytes = data as &[u8];
+            ty::ValTree::from_raw_bytes(tcx, bytes)
         }
         (ast::LitKind::ByteStr(data), ty::Ref(_, inner_ty, _)) if inner_ty.is_array() => {
-            let id = tcx.allocate_bytes(data);
-            ConstValue::Scalar(Scalar::from_pointer(id.into(), &tcx))
+            let bytes = data as &[u8];
+            ty::ValTree::from_raw_bytes(tcx, bytes)
         }
         (ast::LitKind::Byte(n), ty::Uint(ty::UintTy::U8)) => {
-            ConstValue::Scalar(Scalar::from_uint(*n, Size::from_bytes(1)))
+            ty::ValTree::from_scalar_int((*n).into())
         }
         (ast::LitKind::Int(n, _), ty::Uint(_)) | (ast::LitKind::Int(n, _), ty::Int(_)) => {
-            trunc(if neg { (*n as i128).overflowing_neg().0 as u128 } else { *n })?
+            let scalar_int =
+                trunc(if neg { (*n as i128).overflowing_neg().0 as u128 } else { *n })?;
+            ty::ValTree::from_scalar_int(scalar_int)
         }
-        (ast::LitKind::Float(n, _), ty::Float(fty)) => {
-            parse_float(*n, *fty, neg).ok_or(LitToConstError::Reported)?
-        }
-        (ast::LitKind::Bool(b), ty::Bool) => ConstValue::Scalar(Scalar::from_bool(*b)),
-        (ast::LitKind::Char(c), ty::Char) => ConstValue::Scalar(Scalar::from_char(*c)),
+        (ast::LitKind::Bool(b), ty::Bool) => ty::ValTree::from_scalar_int((*b).into()),
+        (ast::LitKind::Char(c), ty::Char) => ty::ValTree::from_scalar_int((*c).into()),
         (ast::LitKind::Err(_), _) => return Err(LitToConstError::Reported),
         _ => return Err(LitToConstError::TypeError),
     };
-    Ok(ty::Const::from_value(tcx, lit, ty))
-}
 
-// FIXME move this to rustc_mir_build::build
-pub(crate) fn parse_float<'tcx>(
-    num: Symbol,
-    fty: ty::FloatTy,
-    neg: bool,
-) -> Option<ConstValue<'tcx>> {
-    let num = num.as_str();
-    use rustc_apfloat::ieee::{Double, Single};
-    let scalar = match fty {
-        ty::FloatTy::F32 => {
-            let Ok(rust_f) = num.parse::<f32>() else { return None };
-            let mut f = num.parse::<Single>().unwrap_or_else(|e| {
-                panic!("apfloat::ieee::Single failed to parse `{}`: {:?}", num, e)
-            });
-            assert!(
-                u128::from(rust_f.to_bits()) == f.to_bits(),
-                "apfloat::ieee::Single gave different result for `{}`: \
-                 {}({:#x}) vs Rust's {}({:#x})",
-                rust_f,
-                f,
-                f.to_bits(),
-                Single::from_bits(rust_f.to_bits().into()),
-                rust_f.to_bits()
-            );
-            if neg {
-                f = -f;
-            }
-            Scalar::from_f32(f)
-        }
-        ty::FloatTy::F64 => {
-            let Ok(rust_f) = num.parse::<f64>() else { return None };
-            let mut f = num.parse::<Double>().unwrap_or_else(|e| {
-                panic!("apfloat::ieee::Double failed to parse `{}`: {:?}", num, e)
-            });
-            assert!(
-                u128::from(rust_f.to_bits()) == f.to_bits(),
-                "apfloat::ieee::Double gave different result for `{}`: \
-                 {}({:#x}) vs Rust's {}({:#x})",
-                rust_f,
-                f,
-                f.to_bits(),
-                Double::from_bits(rust_f.to_bits().into()),
-                rust_f.to_bits()
-            );
-            if neg {
-                f = -f;
-            }
-            Scalar::from_f64(f)
-        }
-    };
-
-    Some(ConstValue::Scalar(scalar))
+    Ok(ty::Const::from_value(tcx, valtree, ty))
 }
diff --git a/compiler/rustc_mir_build/src/thir/cx/block.rs b/compiler/rustc_mir_build/src/thir/cx/block.rs
index 2d9b5c1..59750d5d 100644
--- a/compiler/rustc_mir_build/src/thir/cx/block.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/block.rs
@@ -6,9 +6,10 @@
 use rustc_middle::ty;
 
 use rustc_index::vec::Idx;
+use rustc_middle::ty::CanonicalUserTypeAnnotation;
 
 impl<'tcx> Cx<'tcx> {
-    crate fn mirror_block(&mut self, block: &'tcx hir::Block<'tcx>) -> Block {
+    pub(crate) fn mirror_block(&mut self, block: &'tcx hir::Block<'tcx>) -> Block {
         // We have to eagerly lower the "spine" of the statements
         // in order to get the lexical scoping correctly.
         let stmts = self.mirror_stmts(block.hir_id.local_id, block.stmts);
@@ -74,19 +75,24 @@
                         };
 
                         let mut pattern = self.pattern_from_hir(local.pat);
+                        debug!(?pattern);
 
                         if let Some(ty) = &local.ty {
                             if let Some(&user_ty) =
                                 self.typeck_results.user_provided_types().get(ty.hir_id)
                             {
                                 debug!("mirror_stmts: user_ty={:?}", user_ty);
+                                let annotation = CanonicalUserTypeAnnotation {
+                                    user_ty,
+                                    span: ty.span,
+                                    inferred_ty: self.typeck_results.node_type(ty.hir_id),
+                                };
                                 pattern = Pat {
                                     ty: pattern.ty,
                                     span: pattern.span,
                                     kind: Box::new(PatKind::AscribeUserType {
                                         ascription: Ascription {
-                                            user_ty: PatTyProj::from_user_type(user_ty),
-                                            user_ty_span: ty.span,
+                                            annotation,
                                             variance: ty::Variance::Covariant,
                                         },
                                         subpattern: pattern,
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index 147c136..b5f3cd8 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -22,17 +22,18 @@
 use rustc_target::abi::VariantIdx;
 
 impl<'tcx> Cx<'tcx> {
-    crate fn mirror_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) -> ExprId {
+    pub(crate) fn mirror_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) -> ExprId {
         // `mirror_expr` is recursing very deep. Make sure the stack doesn't overflow.
         ensure_sufficient_stack(|| self.mirror_expr_inner(expr))
     }
 
-    crate fn mirror_exprs(&mut self, exprs: &'tcx [hir::Expr<'tcx>]) -> Box<[ExprId]> {
+    pub(crate) fn mirror_exprs(&mut self, exprs: &'tcx [hir::Expr<'tcx>]) -> Box<[ExprId]> {
         exprs.iter().map(|expr| self.mirror_expr_inner(expr)).collect()
     }
 
     pub(super) fn mirror_expr_inner(&mut self, hir_expr: &'tcx hir::Expr<'tcx>) -> ExprId {
-        let temp_lifetime = self.region_scope_tree.temporary_scope(hir_expr.hir_id.local_id);
+        let temp_lifetime =
+            self.rvalue_scopes.temporary_scope(self.region_scope_tree, hir_expr.hir_id.local_id);
         let expr_scope =
             region::Scope { id: hir_expr.hir_id.local_id, data: region::ScopeData::Node };
 
@@ -161,7 +162,8 @@
         let tcx = self.tcx;
         let expr_ty = self.typeck_results().expr_ty(expr);
         let expr_span = expr.span;
-        let temp_lifetime = self.region_scope_tree.temporary_scope(expr.hir_id.local_id);
+        let temp_lifetime =
+            self.rvalue_scopes.temporary_scope(self.region_scope_tree, expr.hir_id.local_id);
 
         let kind = match expr.kind {
             // Here comes the interesting stuff:
@@ -416,7 +418,7 @@
                 }
             },
 
-            hir::ExprKind::Closure(..) => {
+            hir::ExprKind::Closure { .. } => {
                 let closure_ty = self.typeck_results().expr_ty(expr);
                 let (def_id, substs, movability) = match *closure_ty.kind() {
                     ty::Closure(def_id, substs) => (def_id, UpvarSubsts::Closure(substs), None),
@@ -575,7 +577,9 @@
             },
             hir::ExprKind::Loop(ref body, ..) => {
                 let block_ty = self.typeck_results().node_type(body.hir_id);
-                let temp_lifetime = self.region_scope_tree.temporary_scope(body.hir_id.local_id);
+                let temp_lifetime = self
+                    .rvalue_scopes
+                    .temporary_scope(self.region_scope_tree, body.hir_id.local_id);
                 let block = self.mirror_block(body);
                 let body = self.thir.exprs.push(Expr {
                     ty: block_ty,
@@ -587,6 +591,7 @@
             }
             hir::ExprKind::Field(ref source, ..) => ExprKind::Field {
                 lhs: self.mirror_expr(source),
+                variant_index: VariantIdx::new(0),
                 name: Field::new(tcx.field_index(expr.hir_id, self.typeck_results)),
             },
             hir::ExprKind::Cast(ref source, ref cast_ty) => {
@@ -776,7 +781,8 @@
         span: Span,
         overloaded_callee: Option<(DefId, SubstsRef<'tcx>)>,
     ) -> Expr<'tcx> {
-        let temp_lifetime = self.region_scope_tree.temporary_scope(expr.hir_id.local_id);
+        let temp_lifetime =
+            self.rvalue_scopes.temporary_scope(self.region_scope_tree, expr.hir_id.local_id);
         let (def_id, substs, user_ty) = match overloaded_callee {
             Some((def_id, substs)) => (def_id, substs, None),
             None => {
@@ -798,8 +804,8 @@
             pattern: self.pattern_from_hir(&arm.pat),
             guard: arm.guard.as_ref().map(|g| match g {
                 hir::Guard::If(ref e) => Guard::If(self.mirror_expr(e)),
-                hir::Guard::IfLet(ref pat, ref e) => {
-                    Guard::IfLet(self.pattern_from_hir(pat), self.mirror_expr(e))
+                hir::Guard::IfLet(ref l) => {
+                    Guard::IfLet(self.pattern_from_hir(l.pat), self.mirror_expr(l.init))
                 }
             }),
             body: self.mirror_expr(arm.body),
@@ -863,7 +869,9 @@
             // a constant reference (or constant raw pointer for `static mut`) in MIR
             Res::Def(DefKind::Static(_), id) => {
                 let ty = self.tcx.static_ptr_ty(id);
-                let temp_lifetime = self.region_scope_tree.temporary_scope(expr.hir_id.local_id);
+                let temp_lifetime = self
+                    .rvalue_scopes
+                    .temporary_scope(self.region_scope_tree, expr.hir_id.local_id);
                 let kind = if self.tcx.is_thread_local_static(id) {
                     ExprKind::ThreadLocalRef(id)
                 } else {
@@ -895,9 +903,12 @@
         );
 
         if is_upvar {
-            ExprKind::UpvarRef { closure_def_id: self.body_owner, var_hir_id }
+            ExprKind::UpvarRef {
+                closure_def_id: self.body_owner,
+                var_hir_id: LocalVarId(var_hir_id),
+            }
         } else {
-            ExprKind::VarRef { id: var_hir_id }
+            ExprKind::VarRef { id: LocalVarId(var_hir_id) }
         }
     }
 
@@ -939,7 +950,8 @@
 
         // construct the complete expression `foo()` for the overloaded call,
         // which will yield the &T type
-        let temp_lifetime = self.region_scope_tree.temporary_scope(expr.hir_id.local_id);
+        let temp_lifetime =
+            self.rvalue_scopes.temporary_scope(self.region_scope_tree, expr.hir_id.local_id);
         let fun = self.method_callee(expr, span, overloaded_callee);
         let fun = self.thir.exprs.push(fun);
         let fun_ty = self.thir[fun].ty;
@@ -959,7 +971,9 @@
         closure_expr: &'tcx hir::Expr<'tcx>,
         place: HirPlace<'tcx>,
     ) -> Expr<'tcx> {
-        let temp_lifetime = self.region_scope_tree.temporary_scope(closure_expr.hir_id.local_id);
+        let temp_lifetime = self
+            .rvalue_scopes
+            .temporary_scope(self.region_scope_tree, closure_expr.hir_id.local_id);
         let var_ty = place.base_ty;
 
         // The result of capture analysis in `rustc_typeck/check/upvar.rs`represents a captured path
@@ -984,14 +998,11 @@
                 HirProjectionKind::Deref => {
                     ExprKind::Deref { arg: self.thir.exprs.push(captured_place_expr) }
                 }
-                HirProjectionKind::Field(field, ..) => {
-                    // Variant index will always be 0, because for multi-variant
-                    // enums, we capture the enum entirely.
-                    ExprKind::Field {
-                        lhs: self.thir.exprs.push(captured_place_expr),
-                        name: Field::new(field as usize),
-                    }
-                }
+                HirProjectionKind::Field(field, variant_index) => ExprKind::Field {
+                    lhs: self.thir.exprs.push(captured_place_expr),
+                    variant_index,
+                    name: Field::new(field as usize),
+                },
                 HirProjectionKind::Index | HirProjectionKind::Subslice => {
                     // We don't capture these projections, so we can ignore them here
                     continue;
@@ -1014,7 +1025,9 @@
         let upvar_capture = captured_place.info.capture_kind;
         let captured_place_expr =
             self.convert_captured_hir_place(closure_expr, captured_place.place.clone());
-        let temp_lifetime = self.region_scope_tree.temporary_scope(closure_expr.hir_id.local_id);
+        let temp_lifetime = self
+            .rvalue_scopes
+            .temporary_scope(self.region_scope_tree, closure_expr.hir_id.local_id);
 
         match upvar_capture {
             ty::UpvarCapture::ByValue => captured_place_expr,
diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs
index f17fe38..d853a5e 100644
--- a/compiler/rustc_mir_build/src/thir/cx/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs
@@ -5,6 +5,7 @@
 use crate::thir::pattern::pat_from_hir;
 use crate::thir::util::UserAnnotatedTyHelpers;
 
+use rustc_ast as ast;
 use rustc_data_structures::steal::Steal;
 use rustc_errors::ErrorGuaranteed;
 use rustc_hir as hir;
@@ -12,11 +13,13 @@
 use rustc_hir::HirId;
 use rustc_hir::Node;
 use rustc_middle::middle::region;
+use rustc_middle::mir::interpret::{LitToConstError, LitToConstInput};
+use rustc_middle::mir::ConstantKind;
 use rustc_middle::thir::*;
-use rustc_middle::ty::{self, TyCtxt};
+use rustc_middle::ty::{self, RvalueScopes, Ty, TyCtxt};
 use rustc_span::Span;
 
-crate fn thir_body<'tcx>(
+pub(crate) fn thir_body<'tcx>(
     tcx: TyCtxt<'tcx>,
     owner_def: ty::WithOptConstParam<LocalDefId>,
 ) -> Result<(&'tcx Steal<Thir<'tcx>>, ExprId), ErrorGuaranteed> {
@@ -30,7 +33,7 @@
     Ok((tcx.alloc_steal_thir(cx.thir), expr))
 }
 
-crate fn thir_tree<'tcx>(
+pub(crate) fn thir_tree<'tcx>(
     tcx: TyCtxt<'tcx>,
     owner_def: ty::WithOptConstParam<LocalDefId>,
 ) -> String {
@@ -44,10 +47,11 @@
     tcx: TyCtxt<'tcx>,
     thir: Thir<'tcx>,
 
-    crate param_env: ty::ParamEnv<'tcx>,
+    pub(crate) param_env: ty::ParamEnv<'tcx>,
 
-    crate region_scope_tree: &'tcx region::ScopeTree,
-    crate typeck_results: &'tcx ty::TypeckResults<'tcx>,
+    pub(crate) region_scope_tree: &'tcx region::ScopeTree,
+    pub(crate) typeck_results: &'tcx ty::TypeckResults<'tcx>,
+    pub(crate) rvalue_scopes: &'tcx RvalueScopes,
 
     /// When applying adjustments to the expression
     /// with the given `HirId`, use the given `Span`,
@@ -70,12 +74,32 @@
             param_env: tcx.param_env(def.did),
             region_scope_tree: tcx.region_scope_tree(def.did),
             typeck_results,
+            rvalue_scopes: &typeck_results.rvalue_scopes,
             body_owner: def.did.to_def_id(),
             adjustment_span: None,
         }
     }
 
-    crate fn pattern_from_hir(&mut self, p: &hir::Pat<'_>) -> Pat<'tcx> {
+    #[instrument(skip(self), level = "debug")]
+    pub(crate) fn const_eval_literal(
+        &mut self,
+        lit: &'tcx ast::LitKind,
+        ty: Ty<'tcx>,
+        sp: Span,
+        neg: bool,
+    ) -> ConstantKind<'tcx> {
+        match self.tcx.at(sp).lit_to_mir_constant(LitToConstInput { lit, ty, neg }) {
+            Ok(c) => c,
+            Err(LitToConstError::Reported) => {
+                // create a dummy value and continue compiling
+                ConstantKind::Ty(self.tcx.const_error(ty))
+            }
+            Err(LitToConstError::TypeError) => bug!("const_eval_literal: had type error"),
+        }
+    }
+
+    #[tracing::instrument(level = "debug", skip(self))]
+    pub(crate) fn pattern_from_hir(&mut self, p: &hir::Pat<'_>) -> Pat<'tcx> {
         let p = match self.tcx.hir().get(p.hir_id) {
             Node::Pat(p) | Node::Binding(p) => p,
             node => bug!("pattern became {:?}", node),
diff --git a/compiler/rustc_mir_build/src/thir/mod.rs b/compiler/rustc_mir_build/src/thir/mod.rs
index ddbe1b0..e0e6ac2 100644
--- a/compiler/rustc_mir_build/src/thir/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/mod.rs
@@ -4,10 +4,10 @@
 //! unit-tested and separated from the Rust source and compiler data
 //! structures.
 
-crate mod constant;
+pub(crate) mod constant;
 
-crate mod cx;
+pub(crate) mod cx;
 
-crate mod pattern;
+pub(crate) mod pattern;
 
 mod util;
diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
index 58e484e..76333b7 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -23,7 +23,7 @@
 use rustc_span::source_map::Spanned;
 use rustc_span::{BytePos, DesugaringKind, ExpnKind, Span};
 
-crate fn check_match(tcx: TyCtxt<'_>, def_id: DefId) {
+pub(crate) fn check_match(tcx: TyCtxt<'_>, def_id: DefId) {
     let body_id = match def_id.as_local() {
         None => return,
         Some(id) => tcx.hir().body_owned_by(tcx.hir().local_def_id_to_hir_id(id)),
@@ -173,10 +173,10 @@
         for arm in hir_arms {
             // Check the arm for some things unrelated to exhaustiveness.
             self.check_patterns(&arm.pat, Refutable);
-            if let Some(hir::Guard::IfLet(ref pat, _)) = arm.guard {
-                self.check_patterns(pat, Refutable);
-                let tpat = self.lower_pattern(&mut cx, pat, &mut false);
-                self.check_let_reachability(&mut cx, pat.hir_id, tpat, tpat.span());
+            if let Some(hir::Guard::IfLet(ref let_expr)) = arm.guard {
+                self.check_patterns(let_expr.pat, Refutable);
+                let tpat = self.lower_pattern(&mut cx, let_expr.pat, &mut false);
+                self.check_let_reachability(&mut cx, let_expr.pat.hir_id, tpat, tpat.span());
             }
         }
 
@@ -803,7 +803,7 @@
     let mut suggestion = None;
     let sm = cx.tcx.sess.source_map();
     match arms {
-        [] if sp.ctxt() == expr_span.ctxt() => {
+        [] if sp.eq_ctxt(expr_span) => {
             // Get the span for the empty match body `{}`.
             let (indentation, more) = if let Some(snippet) = sm.indentation_before(sp) {
                 (format!("\n{}", snippet), "    ")
@@ -821,24 +821,36 @@
             ));
         }
         [only] => {
-            let pre_indentation = if let (Some(snippet), true) = (
-                sm.indentation_before(only.span),
-                sm.is_multiline(sp.shrink_to_hi().with_hi(only.span.lo())),
-            ) {
-                format!("\n{}", snippet)
+            let (pre_indentation, is_multiline) = if let Some(snippet) = sm.indentation_before(only.span)
+                && let Ok(with_trailing) = sm.span_extend_while(only.span, |c| c.is_whitespace() || c == ',')
+                && sm.is_multiline(with_trailing)
+            {
+                (format!("\n{}", snippet), true)
             } else {
-                " ".to_string()
+                (" ".to_string(), false)
             };
-            let comma = if matches!(only.body.kind, hir::ExprKind::Block(..)) { "" } else { "," };
+            let comma = if matches!(only.body.kind, hir::ExprKind::Block(..))
+                && only.span.eq_ctxt(only.body.span)
+                && is_multiline
+            {
+                ""
+            } else {
+                ","
+            };
             suggestion = Some((
                 only.span.shrink_to_hi(),
                 format!("{}{}{} => todo!()", comma, pre_indentation, pattern),
             ));
         }
-        [.., prev, last] if prev.span.ctxt() == last.span.ctxt() => {
+        [.., prev, last] if prev.span.eq_ctxt(last.span) => {
             if let Ok(snippet) = sm.span_to_snippet(prev.span.between(last.span)) {
-                let comma =
-                    if matches!(last.body.kind, hir::ExprKind::Block(..)) { "" } else { "," };
+                let comma = if matches!(last.body.kind, hir::ExprKind::Block(..))
+                    && last.span.eq_ctxt(last.body.span)
+                {
+                    ""
+                } else {
+                    ","
+                };
                 suggestion = Some((
                     last.span.shrink_to_hi(),
                     format!(
@@ -880,7 +892,7 @@
     err.emit();
 }
 
-crate fn joined_uncovered_patterns<'p, 'tcx>(
+pub(crate) fn joined_uncovered_patterns<'p, 'tcx>(
     cx: &MatchCheckCtxt<'p, 'tcx>,
     witnesses: &[DeconstructedPat<'p, 'tcx>],
 ) -> String {
@@ -901,7 +913,7 @@
     }
 }
 
-crate fn pattern_not_covered_label(
+pub(crate) fn pattern_not_covered_label(
     witnesses: &[DeconstructedPat<'_, '_>],
     joined_patterns: &str,
 ) -> String {
@@ -1108,9 +1120,9 @@
 
     match parent_node {
         hir::Node::Arm(hir::Arm {
-            guard: Some(hir::Guard::IfLet(&hir::Pat { hir_id, .. }, _)),
+            guard: Some(hir::Guard::IfLet(&hir::Let { pat: hir::Pat { hir_id, .. }, .. })),
             ..
-        }) if Some(hir_id) == pat_id => {
+        }) if Some(*hir_id) == pat_id => {
             return LetSource::IfLetGuard;
         }
         hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Let(..), span, .. }) => {
diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
index 2298cc7..845be2a 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
@@ -1,7 +1,7 @@
 use rustc_hir as hir;
 use rustc_index::vec::Idx;
 use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
-use rustc_middle::mir::Field;
+use rustc_middle::mir::{self, Field};
 use rustc_middle::thir::{FieldPat, Pat, PatKind};
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt};
@@ -22,7 +22,7 @@
     #[instrument(level = "debug", skip(self))]
     pub(super) fn const_to_pat(
         &self,
-        cv: ty::Const<'tcx>,
+        cv: mir::ConstantKind<'tcx>,
         id: hir::HirId,
         span: Span,
         mir_structural_match_violation: bool,
@@ -121,27 +121,27 @@
 
     fn search_for_structural_match_violation(&self, ty: Ty<'tcx>) -> Option<String> {
         traits::search_for_structural_match_violation(self.span, self.tcx(), ty).map(|non_sm_ty| {
-            with_no_trimmed_paths!(match non_sm_ty {
-                traits::NonStructuralMatchTy::Adt(adt) => self.adt_derive_msg(adt),
-                traits::NonStructuralMatchTy::Dynamic => {
+            with_no_trimmed_paths!(match non_sm_ty.kind {
+                traits::NonStructuralMatchTyKind::Adt(adt) => self.adt_derive_msg(adt),
+                traits::NonStructuralMatchTyKind::Dynamic => {
                     "trait objects cannot be used in patterns".to_string()
                 }
-                traits::NonStructuralMatchTy::Opaque => {
+                traits::NonStructuralMatchTyKind::Opaque => {
                     "opaque types cannot be used in patterns".to_string()
                 }
-                traits::NonStructuralMatchTy::Closure => {
+                traits::NonStructuralMatchTyKind::Closure => {
                     "closures cannot be used in patterns".to_string()
                 }
-                traits::NonStructuralMatchTy::Generator => {
+                traits::NonStructuralMatchTyKind::Generator => {
                     "generators cannot be used in patterns".to_string()
                 }
-                traits::NonStructuralMatchTy::Param => {
+                traits::NonStructuralMatchTyKind::Param => {
                     bug!("use of a constant whose type is a parameter inside a pattern")
                 }
-                traits::NonStructuralMatchTy::Projection => {
+                traits::NonStructuralMatchTyKind::Projection => {
                     bug!("use of a constant whose type is a projection inside a pattern")
                 }
-                traits::NonStructuralMatchTy::Foreign => {
+                traits::NonStructuralMatchTyKind::Foreign => {
                     bug!("use of a value of a foreign type inside a pattern")
                 }
             })
@@ -152,7 +152,11 @@
         ty.is_structural_eq_shallow(self.infcx.tcx)
     }
 
-    fn to_pat(&mut self, cv: ty::Const<'tcx>, mir_structural_match_violation: bool) -> Pat<'tcx> {
+    fn to_pat(
+        &mut self,
+        cv: mir::ConstantKind<'tcx>,
+        mir_structural_match_violation: bool,
+    ) -> Pat<'tcx> {
         trace!(self.treat_byte_string_as_slice);
         // This method is just a wrapper handling a validity check; the heavy lifting is
         // performed by the recursive `recur` method, which is not meant to be
@@ -246,7 +250,7 @@
 
     fn field_pats(
         &self,
-        vals: impl Iterator<Item = ty::Const<'tcx>>,
+        vals: impl Iterator<Item = mir::ConstantKind<'tcx>>,
     ) -> Result<Vec<FieldPat<'tcx>>, FallbackToConstRef> {
         vals.enumerate()
             .map(|(idx, val)| {
@@ -257,9 +261,10 @@
     }
 
     // Recursive helper for `to_pat`; invoke that (instead of calling this directly).
+    #[instrument(skip(self), level = "debug")]
     fn recur(
         &self,
-        cv: ty::Const<'tcx>,
+        cv: mir::ConstantKind<'tcx>,
         mir_structural_match_violation: bool,
     ) -> Result<Pat<'tcx>, FallbackToConstRef> {
         let id = self.id;
@@ -365,7 +370,8 @@
                 PatKind::Wild
             }
             ty::Adt(adt_def, substs) if adt_def.is_enum() => {
-                let destructured = tcx.destructure_const(param_env.and(cv));
+                let destructured = tcx.destructure_mir_constant(param_env, cv);
+
                 PatKind::Variant {
                     adt_def: *adt_def,
                     substs,
@@ -376,12 +382,12 @@
                 }
             }
             ty::Tuple(_) | ty::Adt(_, _) => {
-                let destructured = tcx.destructure_const(param_env.and(cv));
+                let destructured = tcx.destructure_mir_constant(param_env, cv);
                 PatKind::Leaf { subpatterns: self.field_pats(destructured.fields.iter().copied())? }
             }
             ty::Array(..) => PatKind::Array {
                 prefix: tcx
-                    .destructure_const(param_env.and(cv))
+                    .destructure_mir_constant(param_env, cv)
                     .fields
                     .iter()
                     .map(|val| self.recur(*val, false))
@@ -412,12 +418,12 @@
                 // arrays.
                 ty::Array(..) if !self.treat_byte_string_as_slice => {
                     let old = self.behind_reference.replace(true);
-                    let array = tcx.deref_const(self.param_env.and(cv));
+                    let array = tcx.deref_mir_constant(self.param_env.and(cv));
                     let val = PatKind::Deref {
                         subpattern: Pat {
                             kind: Box::new(PatKind::Array {
                                 prefix: tcx
-                                    .destructure_const(param_env.and(array))
+                                    .destructure_mir_constant(param_env, array)
                                     .fields
                                     .iter()
                                     .map(|val| self.recur(*val, false))
@@ -438,12 +444,12 @@
                 // pattern.
                 ty::Slice(elem_ty) => {
                     let old = self.behind_reference.replace(true);
-                    let array = tcx.deref_const(self.param_env.and(cv));
+                    let array = tcx.deref_mir_constant(self.param_env.and(cv));
                     let val = PatKind::Deref {
                         subpattern: Pat {
                             kind: Box::new(PatKind::Slice {
                                 prefix: tcx
-                                    .destructure_const(param_env.and(array))
+                                    .destructure_mir_constant(param_env, array)
                                     .fields
                                     .iter()
                                     .map(|val| self.recur(*val, false))
@@ -497,7 +503,7 @@
                 // deref pattern.
                 _ => {
                     if !pointee_ty.is_sized(tcx.at(span), param_env) {
-                        // `tcx.deref_const()` below will ICE with an unsized type
+                        // `tcx.deref_mir_constant()` below will ICE with an unsized type
                         // (except slices, which are handled in a separate arm above).
                         let msg = format!("cannot use unsized non-slice type `{}` in constant patterns", pointee_ty);
                         if self.include_lint_checks {
@@ -512,7 +518,7 @@
                         // we fall back to a const pattern. If we do not do this, we may end up with
                         // a !structural-match constant that is not of reference type, which makes it
                         // very hard to invoke `PartialEq::eq` on it as a fallback.
-                        let val = match self.recur(tcx.deref_const(self.param_env.and(cv)), false) {
+                        let val = match self.recur(tcx.deref_mir_constant(self.param_env.and(cv)), false) {
                             Ok(subpattern) => PatKind::Deref { subpattern },
                             Err(_) => PatKind::Constant { value: cv },
                         };
diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
index 60eead6..60db980 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
@@ -52,7 +52,7 @@
 use rustc_index::vec::Idx;
 
 use rustc_hir::{HirId, RangeEnd};
-use rustc_middle::mir::Field;
+use rustc_middle::mir::{self, Field};
 use rustc_middle::thir::{FieldPat, Pat, PatKind, PatRange};
 use rustc_middle::ty::layout::IntegerExt;
 use rustc_middle::ty::{self, Ty, TyCtxt, VariantDef};
@@ -133,23 +133,35 @@
     }
 
     #[inline]
-    fn from_const<'tcx>(
+    fn from_constant<'tcx>(
         tcx: TyCtxt<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
-        value: ty::Const<'tcx>,
+        value: mir::ConstantKind<'tcx>,
     ) -> Option<IntRange> {
         let ty = value.ty();
         if let Some((target_size, bias)) = Self::integral_size_and_signed_bias(tcx, ty) {
             let val = (|| {
-                if let ty::ConstKind::Value(ConstValue::Scalar(scalar)) = value.val() {
-                    // For this specific pattern we can skip a lot of effort and go
-                    // straight to the result, after doing a bit of checking. (We
-                    // could remove this branch and just fall through, which
-                    // is more general but much slower.)
-                    if let Ok(bits) = scalar.to_bits_or_ptr_internal(target_size).unwrap() {
-                        return Some(bits);
+                match value {
+                    mir::ConstantKind::Val(ConstValue::Scalar(scalar), _) => {
+                        // For this specific pattern we can skip a lot of effort and go
+                        // straight to the result, after doing a bit of checking. (We
+                        // could remove this branch and just fall through, which
+                        // is more general but much slower.)
+                        if let Ok(Ok(bits)) = scalar.to_bits_or_ptr_internal(target_size) {
+                            return Some(bits);
+                        } else {
+                            return None;
+                        }
                     }
+                    mir::ConstantKind::Ty(c) => match c.kind() {
+                        ty::ConstKind::Value(_) => bug!(
+                            "encountered ConstValue in mir::ConstantKind::Ty, whereas this is expected to be in ConstantKind::Val"
+                        ),
+                        _ => {}
+                    },
+                    _ => {}
                 }
+
                 // This is a more general form of the previous case.
                 value.try_eval_bits(tcx, param_env, ty)
             })()?;
@@ -234,8 +246,8 @@
         let (lo, hi) = (lo ^ bias, hi ^ bias);
 
         let env = ty::ParamEnv::empty().and(ty);
-        let lo_const = ty::Const::from_bits(tcx, lo, env);
-        let hi_const = ty::Const::from_bits(tcx, hi, env);
+        let lo_const = mir::ConstantKind::from_bits(tcx, lo, env);
+        let hi_const = mir::ConstantKind::from_bits(tcx, hi, env);
 
         let kind = if lo == hi {
             PatKind::Constant { value: lo_const }
@@ -635,9 +647,9 @@
     /// Ranges of integer literal values (`2`, `2..=5` or `2..5`).
     IntRange(IntRange),
     /// Ranges of floating-point literal values (`2.0..=5.2`).
-    FloatRange(ty::Const<'tcx>, ty::Const<'tcx>, RangeEnd),
+    FloatRange(mir::ConstantKind<'tcx>, mir::ConstantKind<'tcx>, RangeEnd),
     /// String literals. Strings are not quite the same as `&[u8]` so we treat them separately.
-    Str(ty::Const<'tcx>),
+    Str(mir::ConstantKind<'tcx>),
     /// Array and slice patterns.
     Slice(Slice),
     /// Constants that must not be matched structurally. They are treated as black
@@ -816,14 +828,8 @@
                 FloatRange(other_from, other_to, other_end),
             ) => {
                 match (
-                    compare_const_vals(pcx.cx.tcx, *self_to, *other_to, pcx.cx.param_env, pcx.ty),
-                    compare_const_vals(
-                        pcx.cx.tcx,
-                        *self_from,
-                        *other_from,
-                        pcx.cx.param_env,
-                        pcx.ty,
-                    ),
+                    compare_const_vals(pcx.cx.tcx, *self_to, *other_to, pcx.cx.param_env),
+                    compare_const_vals(pcx.cx.tcx, *self_from, *other_from, pcx.cx.param_env),
                 ) {
                     (Some(to), Some(from)) => {
                         (from == Ordering::Greater || from == Ordering::Equal)
@@ -836,16 +842,7 @@
             (Str(self_val), Str(other_val)) => {
                 // FIXME Once valtrees are available we can directly use the bytes
                 // in the `Str` variant of the valtree for the comparison here.
-                match compare_const_vals(
-                    pcx.cx.tcx,
-                    *self_val,
-                    *other_val,
-                    pcx.cx.param_env,
-                    pcx.ty,
-                ) {
-                    Some(comparison) => comparison == Ordering::Equal,
-                    None => false,
-                }
+                self_val == other_val
             }
             (Slice(self_slice), Slice(other_slice)) => self_slice.is_covered_by(*other_slice),
 
@@ -1376,7 +1373,7 @@
                 }
             }
             PatKind::Constant { value } => {
-                if let Some(int_range) = IntRange::from_const(cx.tcx, cx.param_env, *value) {
+                if let Some(int_range) = IntRange::from_constant(cx.tcx, cx.param_env, *value) {
                     ctor = IntRange(int_range);
                     fields = Fields::empty();
                 } else {
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index 5b0aa43..a13748a 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -15,34 +15,36 @@
 use rustc_hir::pat_util::EnumerateAndAdjustIterator;
 use rustc_hir::RangeEnd;
 use rustc_index::vec::Idx;
-use rustc_middle::mir::interpret::{get_slice_bytes, ConstValue};
-use rustc_middle::mir::interpret::{ErrorHandled, LitToConstError, LitToConstInput};
-use rustc_middle::mir::UserTypeProjection;
+use rustc_middle::mir::interpret::{
+    ConstValue, ErrorHandled, LitToConstError, LitToConstInput, Scalar,
+};
+use rustc_middle::mir::{self, UserTypeProjection};
 use rustc_middle::mir::{BorrowKind, Field, Mutability};
-use rustc_middle::thir::{Ascription, BindingMode, FieldPat, Pat, PatKind, PatRange, PatTyProj};
+use rustc_middle::thir::{Ascription, BindingMode, FieldPat, LocalVarId, Pat, PatKind, PatRange};
 use rustc_middle::ty::subst::{GenericArg, SubstsRef};
+use rustc_middle::ty::CanonicalUserTypeAnnotation;
 use rustc_middle::ty::{self, AdtDef, ConstKind, DefIdTree, Region, Ty, TyCtxt, UserType};
 use rustc_span::{Span, Symbol};
 
 use std::cmp::Ordering;
 
 #[derive(Clone, Debug)]
-crate enum PatternError {
+pub(crate) enum PatternError {
     AssocConstInPattern(Span),
     ConstParamInPattern(Span),
     StaticInPattern(Span),
     NonConstPath(Span),
 }
 
-crate struct PatCtxt<'a, 'tcx> {
-    crate tcx: TyCtxt<'tcx>,
-    crate param_env: ty::ParamEnv<'tcx>,
-    crate typeck_results: &'a ty::TypeckResults<'tcx>,
-    crate errors: Vec<PatternError>,
+pub(crate) struct PatCtxt<'a, 'tcx> {
+    pub(crate) tcx: TyCtxt<'tcx>,
+    pub(crate) param_env: ty::ParamEnv<'tcx>,
+    pub(crate) typeck_results: &'a ty::TypeckResults<'tcx>,
+    pub(crate) errors: Vec<PatternError>,
     include_lint_checks: bool,
 }
 
-crate fn pat_from_hir<'a, 'tcx>(
+pub(crate) fn pat_from_hir<'a, 'tcx>(
     tcx: TyCtxt<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
     typeck_results: &'a ty::TypeckResults<'tcx>,
@@ -59,7 +61,7 @@
 }
 
 impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
-    crate fn new(
+    pub(crate) fn new(
         tcx: TyCtxt<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
         typeck_results: &'a ty::TypeckResults<'tcx>,
@@ -67,12 +69,12 @@
         PatCtxt { tcx, param_env, typeck_results, errors: vec![], include_lint_checks: false }
     }
 
-    crate fn include_lint_checks(&mut self) -> &mut Self {
+    pub(crate) fn include_lint_checks(&mut self) -> &mut Self {
         self.include_lint_checks = true;
         self
     }
 
-    crate fn lower_pattern(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Pat<'tcx> {
+    pub(crate) fn lower_pattern(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Pat<'tcx> {
         // When implicit dereferences have been inserted in this pattern, the unadjusted lowered
         // pattern has the type that results *after* dereferencing. For example, in this code:
         //
@@ -121,14 +123,14 @@
     fn lower_pattern_range(
         &mut self,
         ty: Ty<'tcx>,
-        lo: ty::Const<'tcx>,
-        hi: ty::Const<'tcx>,
+        lo: mir::ConstantKind<'tcx>,
+        hi: mir::ConstantKind<'tcx>,
         end: RangeEnd,
         span: Span,
     ) -> PatKind<'tcx> {
         assert_eq!(lo.ty(), ty);
         assert_eq!(hi.ty(), ty);
-        let cmp = compare_const_vals(self.tcx, lo, hi, self.param_env, ty);
+        let cmp = compare_const_vals(self.tcx, lo, hi, self.param_env);
         match (end, cmp) {
             // `x..y` where `x < y`.
             // Non-empty because the range includes at least `x`.
@@ -177,16 +179,18 @@
         ty: Ty<'tcx>,
         lo: Option<&PatKind<'tcx>>,
         hi: Option<&PatKind<'tcx>>,
-    ) -> Option<(ty::Const<'tcx>, ty::Const<'tcx>)> {
+    ) -> Option<(mir::ConstantKind<'tcx>, mir::ConstantKind<'tcx>)> {
         match (lo, hi) {
             (Some(PatKind::Constant { value: lo }), Some(PatKind::Constant { value: hi })) => {
                 Some((*lo, *hi))
             }
             (Some(PatKind::Constant { value: lo }), None) => {
-                Some((*lo, ty.numeric_max_val(self.tcx)?))
+                let hi = ty.numeric_max_val(self.tcx)?;
+                Some((*lo, mir::ConstantKind::from_const(hi, self.tcx)))
             }
             (None, Some(PatKind::Constant { value: hi })) => {
-                Some((ty.numeric_min_val(self.tcx)?, *hi))
+                let lo = ty.numeric_min_val(self.tcx)?;
+                Some((mir::ConstantKind::from_const(lo, self.tcx), *hi))
             }
             _ => None,
         }
@@ -225,7 +229,8 @@
                 for end in &[lo, hi] {
                     if let Some((_, Some(ascription))) = end {
                         let subpattern = Pat { span: pat.span, ty, kind: Box::new(kind) };
-                        kind = PatKind::AscribeUserType { ascription: *ascription, subpattern };
+                        kind =
+                            PatKind::AscribeUserType { ascription: ascription.clone(), subpattern };
                     }
                 }
 
@@ -284,7 +289,7 @@
                     mutability,
                     mode,
                     name: ident.name,
-                    var: id,
+                    var: LocalVarId(id),
                     ty: var_ty,
                     subpattern: self.lower_opt_pattern(sub),
                     is_primary: id == pat.hir_id,
@@ -430,13 +435,14 @@
 
         if let Some(user_ty) = self.user_substs_applied_to_ty_of_hir_id(hir_id) {
             debug!("lower_variant_or_leaf: kind={:?} user_ty={:?} span={:?}", kind, user_ty, span);
+            let annotation = CanonicalUserTypeAnnotation {
+                user_ty,
+                span,
+                inferred_ty: self.typeck_results.node_type(hir_id),
+            };
             kind = PatKind::AscribeUserType {
                 subpattern: Pat { span, ty, kind: Box::new(kind) },
-                ascription: Ascription {
-                    user_ty: PatTyProj::from_user_type(user_ty),
-                    user_ty_span: span,
-                    variance: ty::Variance::Covariant,
-                },
+                ascription: Ascription { annotation, variance: ty::Variance::Covariant },
             };
         }
 
@@ -446,6 +452,7 @@
     /// Takes a HIR Path. If the path is a constant, evaluates it and feeds
     /// it to `const_to_pat`. Any other path (like enum variants without fields)
     /// is converted to the corresponding pattern via `lower_variant_or_leaf`.
+    #[instrument(skip(self), level = "debug")]
     fn lower_path(&mut self, qpath: &hir::QPath<'_>, id: hir::HirId, span: Span) -> Pat<'tcx> {
         let ty = self.typeck_results.node_type(id);
         let res = self.typeck_results.qpath_res(qpath, id);
@@ -487,8 +494,8 @@
         debug!("mir_structural_match_violation({:?}) -> {}", qpath, mir_structural_match_violation);
 
         match self.tcx.const_eval_instance(param_env_reveal_all, instance, Some(span)) {
-            Ok(value) => {
-                let const_ = ty::Const::from_value(self.tcx, value, ty);
+            Ok(literal) => {
+                let const_ = mir::ConstantKind::Val(literal, ty);
                 let pattern = self.const_to_pat(const_, id, span, mir_structural_match_violation);
 
                 if !is_associated_const {
@@ -496,18 +503,21 @@
                 }
 
                 let user_provided_types = self.typeck_results().user_provided_types();
-                if let Some(u_ty) = user_provided_types.get(id) {
-                    let user_ty = PatTyProj::from_user_type(*u_ty);
+                if let Some(&user_ty) = user_provided_types.get(id) {
+                    let annotation = CanonicalUserTypeAnnotation {
+                        user_ty,
+                        span,
+                        inferred_ty: self.typeck_results().node_type(id),
+                    };
                     Pat {
                         span,
                         kind: Box::new(PatKind::AscribeUserType {
                             subpattern: pattern,
                             ascription: Ascription {
+                                annotation,
                                 /// Note that use `Contravariant` here. See the
                                 /// `variance` field documentation for details.
                                 variance: ty::Variance::Contravariant,
-                                user_ty,
-                                user_ty_span: span,
                             },
                         }),
                         ty: const_.ty(),
@@ -537,25 +547,30 @@
         span: Span,
     ) -> PatKind<'tcx> {
         let anon_const_def_id = self.tcx.hir().local_def_id(anon_const.hir_id);
-        let value = ty::Const::from_inline_const(self.tcx, anon_const_def_id);
+        let value = mir::ConstantKind::from_inline_const(self.tcx, anon_const_def_id);
 
         // Evaluate early like we do in `lower_path`.
         let value = value.eval(self.tcx, self.param_env);
 
-        match value.val() {
-            ConstKind::Param(_) => {
-                self.errors.push(PatternError::ConstParamInPattern(span));
-                return PatKind::Wild;
+        match value {
+            mir::ConstantKind::Ty(c) => {
+                match c.kind() {
+                    ConstKind::Param(_) => {
+                        self.errors.push(PatternError::ConstParamInPattern(span));
+                        return PatKind::Wild;
+                    }
+                    ConstKind::Unevaluated(_) => {
+                        // If we land here it means the const can't be evaluated because it's `TooGeneric`.
+                        self.tcx
+                            .sess
+                            .span_err(span, "constant pattern depends on a generic parameter");
+                        return PatKind::Wild;
+                    }
+                    _ => bug!("Expected either ConstKind::Param or ConstKind::Unevaluated"),
+                }
             }
-            ConstKind::Unevaluated(_) => {
-                // If we land here it means the const can't be evaluated because it's `TooGeneric`.
-                self.tcx.sess.span_err(span, "constant pattern depends on a generic parameter");
-                return PatKind::Wild;
-            }
-            _ => (),
+            mir::ConstantKind::Val(_, _) => *self.const_to_pat(value, id, span, false).kind,
         }
-
-        *self.const_to_pat(value, id, span, false).kind
     }
 
     /// Converts literals, paths and negation of literals to patterns.
@@ -582,7 +597,7 @@
 
         let lit_input =
             LitToConstInput { lit: &lit.node, ty: self.typeck_results.expr_ty(expr), neg };
-        match self.tcx.at(expr.span).lit_to_const(lit_input) {
+        match self.tcx.at(expr.span).lit_to_mir_constant(lit_input) {
             Ok(constant) => *self.const_to_pat(constant, expr.hir_id, lit.span, false).kind,
             Err(LitToConstError::Reported) => PatKind::Wild,
             Err(LitToConstError::TypeError) => bug!("lower_lit: had type error"),
@@ -600,7 +615,7 @@
     }
 }
 
-crate trait PatternFoldable<'tcx>: Sized {
+pub(crate) trait PatternFoldable<'tcx>: Sized {
     fn fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
         self.super_fold_with(folder)
     }
@@ -608,7 +623,7 @@
     fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self;
 }
 
-crate trait PatternFolder<'tcx>: Sized {
+pub(crate) trait PatternFolder<'tcx>: Sized {
     fn fold_pattern(&mut self, pattern: &Pat<'tcx>) -> Pat<'tcx> {
         pattern.super_fold_with(self)
     }
@@ -637,7 +652,7 @@
     }
 }
 
-macro_rules! CloneImpls {
+macro_rules! ClonePatternFoldableImpls {
     (<$lt_tcx:tt> $($ty:ty),+) => {
         $(
             impl<$lt_tcx> PatternFoldable<$lt_tcx> for $ty {
@@ -649,11 +664,11 @@
     }
 }
 
-CloneImpls! { <'tcx>
-    Span, Field, Mutability, Symbol, hir::HirId, usize, ty::Const<'tcx>,
+ClonePatternFoldableImpls! { <'tcx>
+    Span, Field, Mutability, Symbol, LocalVarId, usize, ty::Const<'tcx>,
     Region<'tcx>, Ty<'tcx>, BindingMode, AdtDef<'tcx>,
     SubstsRef<'tcx>, &'tcx GenericArg<'tcx>, UserType<'tcx>,
-    UserTypeProjection, PatTyProj<'tcx>
+    UserTypeProjection, CanonicalUserTypeAnnotation<'tcx>
 }
 
 impl<'tcx> PatternFoldable<'tcx> for FieldPat<'tcx> {
@@ -686,14 +701,10 @@
             PatKind::Wild => PatKind::Wild,
             PatKind::AscribeUserType {
                 ref subpattern,
-                ascription: Ascription { variance, ref user_ty, user_ty_span },
+                ascription: Ascription { ref annotation, variance },
             } => PatKind::AscribeUserType {
                 subpattern: subpattern.fold_with(folder),
-                ascription: Ascription {
-                    user_ty: user_ty.fold_with(folder),
-                    variance,
-                    user_ty_span,
-                },
+                ascription: Ascription { annotation: annotation.fold_with(folder), variance },
             },
             PatKind::Binding { mutability, name, mode, var, ty, ref subpattern, is_primary } => {
                 PatKind::Binding {
@@ -738,63 +749,54 @@
 }
 
 #[instrument(skip(tcx), level = "debug")]
-crate fn compare_const_vals<'tcx>(
+pub(crate) fn compare_const_vals<'tcx>(
     tcx: TyCtxt<'tcx>,
-    a: ty::Const<'tcx>,
-    b: ty::Const<'tcx>,
+    a: mir::ConstantKind<'tcx>,
+    b: mir::ConstantKind<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
-    ty: Ty<'tcx>,
 ) -> Option<Ordering> {
-    let from_bool = |v: bool| v.then_some(Ordering::Equal);
+    assert_eq!(a.ty(), b.ty());
 
-    let fallback = || from_bool(a == b);
+    let ty = a.ty();
 
-    // Use the fallback if any type differs
-    if a.ty() != b.ty() || a.ty() != ty {
-        return fallback();
+    // This code is hot when compiling matches with many ranges. So we
+    // special-case extraction of evaluated scalars for speed, for types where
+    // raw data comparisons are appropriate. E.g. `unicode-normalization` has
+    // many ranges such as '\u{037A}'..='\u{037F}', and chars can be compared
+    // in this way.
+    match ty.kind() {
+        ty::Float(_) | ty::Int(_) => {} // require special handling, see below
+        _ => match (a, b) {
+            (
+                mir::ConstantKind::Val(ConstValue::Scalar(Scalar::Int(a)), _a_ty),
+                mir::ConstantKind::Val(ConstValue::Scalar(Scalar::Int(b)), _b_ty),
+            ) => return Some(a.cmp(&b)),
+            _ => {}
+        },
     }
 
-    // Early return for equal constants (so e.g. references to ZSTs can be compared, even if they
-    // are just integer addresses).
-    if a.val() == b.val() {
-        return from_bool(true);
-    }
+    let a = a.eval_bits(tcx, param_env, ty);
+    let b = b.eval_bits(tcx, param_env, ty);
 
-    let a_bits = a.try_eval_bits(tcx, param_env, ty);
-    let b_bits = b.try_eval_bits(tcx, param_env, ty);
-
-    if let (Some(a), Some(b)) = (a_bits, b_bits) {
-        use rustc_apfloat::Float;
-        return match *ty.kind() {
-            ty::Float(ty::FloatTy::F32) => {
-                let l = rustc_apfloat::ieee::Single::from_bits(a);
-                let r = rustc_apfloat::ieee::Single::from_bits(b);
-                l.partial_cmp(&r)
-            }
-            ty::Float(ty::FloatTy::F64) => {
-                let l = rustc_apfloat::ieee::Double::from_bits(a);
-                let r = rustc_apfloat::ieee::Double::from_bits(b);
-                l.partial_cmp(&r)
-            }
-            ty::Int(ity) => {
-                use rustc_middle::ty::layout::IntegerExt;
-                let size = rustc_target::abi::Integer::from_int_ty(&tcx, ity).size();
-                let a = size.sign_extend(a);
-                let b = size.sign_extend(b);
-                Some((a as i128).cmp(&(b as i128)))
-            }
-            _ => Some(a.cmp(&b)),
-        };
+    use rustc_apfloat::Float;
+    match *ty.kind() {
+        ty::Float(ty::FloatTy::F32) => {
+            let a = rustc_apfloat::ieee::Single::from_bits(a);
+            let b = rustc_apfloat::ieee::Single::from_bits(b);
+            a.partial_cmp(&b)
+        }
+        ty::Float(ty::FloatTy::F64) => {
+            let a = rustc_apfloat::ieee::Double::from_bits(a);
+            let b = rustc_apfloat::ieee::Double::from_bits(b);
+            a.partial_cmp(&b)
+        }
+        ty::Int(ity) => {
+            use rustc_middle::ty::layout::IntegerExt;
+            let size = rustc_target::abi::Integer::from_int_ty(&tcx, ity).size();
+            let a = size.sign_extend(a);
+            let b = size.sign_extend(b);
+            Some((a as i128).cmp(&(b as i128)))
+        }
+        _ => Some(a.cmp(&b)),
     }
-
-    if let ty::Str = ty.kind() && let (
-        ty::ConstKind::Value(a_val @ ConstValue::Slice { .. }),
-        ty::ConstKind::Value(b_val @ ConstValue::Slice { .. }),
-    ) = (a.val(), b.val())
-    {
-        let a_bytes = get_slice_bytes(&tcx, a_val);
-        let b_bytes = get_slice_bytes(&tcx, b_val);
-        return from_bool(a_bytes == b_bytes);
-    }
-    fallback()
 }
diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
index 4e96cfd..9e7a267 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
@@ -309,16 +309,16 @@
 use std::fmt;
 use std::iter::once;
 
-crate struct MatchCheckCtxt<'p, 'tcx> {
-    crate tcx: TyCtxt<'tcx>,
+pub(crate) struct MatchCheckCtxt<'p, 'tcx> {
+    pub(crate) tcx: TyCtxt<'tcx>,
     /// The module in which the match occurs. This is necessary for
     /// checking inhabited-ness of types because whether a type is (visibly)
     /// inhabited can depend on whether it was defined in the current module or
     /// not. E.g., `struct Foo { _private: ! }` cannot be seen to be empty
     /// outside its module and should not be matchable with an empty match statement.
-    crate module: DefId,
-    crate param_env: ty::ParamEnv<'tcx>,
-    crate pattern_arena: &'p TypedArena<DeconstructedPat<'p, 'tcx>>,
+    pub(crate) module: DefId,
+    pub(crate) param_env: ty::ParamEnv<'tcx>,
+    pub(crate) pattern_arena: &'p TypedArena<DeconstructedPat<'p, 'tcx>>,
 }
 
 impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> {
@@ -691,7 +691,7 @@
 ///
 /// The final `Pair(Some(_), true)` is then the resulting witness.
 #[derive(Debug)]
-crate struct Witness<'p, 'tcx>(Vec<DeconstructedPat<'p, 'tcx>>);
+pub(crate) struct Witness<'p, 'tcx>(Vec<DeconstructedPat<'p, 'tcx>>);
 
 impl<'p, 'tcx> Witness<'p, 'tcx> {
     /// Asserts that the witness contains a single pattern, and returns it.
@@ -908,16 +908,16 @@
 
 /// The arm of a match expression.
 #[derive(Clone, Copy, Debug)]
-crate struct MatchArm<'p, 'tcx> {
+pub(crate) struct MatchArm<'p, 'tcx> {
     /// The pattern must have been lowered through `check_match::MatchVisitor::lower_pattern`.
-    crate pat: &'p DeconstructedPat<'p, 'tcx>,
-    crate hir_id: HirId,
-    crate has_guard: bool,
+    pub(crate) pat: &'p DeconstructedPat<'p, 'tcx>,
+    pub(crate) hir_id: HirId,
+    pub(crate) has_guard: bool,
 }
 
 /// Indicates whether or not a given arm is reachable.
 #[derive(Clone, Debug)]
-crate enum Reachability {
+pub(crate) enum Reachability {
     /// The arm is reachable. This additionally carries a set of or-pattern branches that have been
     /// found to be unreachable despite the overall arm being reachable. Used only in the presence
     /// of or-patterns, otherwise it stays empty.
@@ -927,12 +927,12 @@
 }
 
 /// The output of checking a match for exhaustiveness and arm reachability.
-crate struct UsefulnessReport<'p, 'tcx> {
+pub(crate) struct UsefulnessReport<'p, 'tcx> {
     /// For each arm of the input, whether that arm is reachable after the arms above it.
-    crate arm_usefulness: Vec<(MatchArm<'p, 'tcx>, Reachability)>,
+    pub(crate) arm_usefulness: Vec<(MatchArm<'p, 'tcx>, Reachability)>,
     /// If the match is exhaustive, this is empty. If not, this contains witnesses for the lack of
     /// exhaustiveness.
-    crate non_exhaustiveness_witnesses: Vec<DeconstructedPat<'p, 'tcx>>,
+    pub(crate) non_exhaustiveness_witnesses: Vec<DeconstructedPat<'p, 'tcx>>,
 }
 
 /// The entrypoint for the usefulness algorithm. Computes whether a match is exhaustive and which
@@ -941,7 +941,7 @@
 /// Note: the input patterns must have been lowered through
 /// `check_match::MatchVisitor::lower_pattern`.
 #[instrument(skip(cx, arms), level = "debug")]
-crate fn compute_match_usefulness<'p, 'tcx>(
+pub(crate) fn compute_match_usefulness<'p, 'tcx>(
     cx: &MatchCheckCtxt<'p, 'tcx>,
     arms: &[MatchArm<'p, 'tcx>],
     scrut_hir_id: HirId,
diff --git a/compiler/rustc_mir_build/src/thir/util.rs b/compiler/rustc_mir_build/src/thir/util.rs
index 82f97f2..c58ed1a 100644
--- a/compiler/rustc_mir_build/src/thir/util.rs
+++ b/compiler/rustc_mir_build/src/thir/util.rs
@@ -1,7 +1,7 @@
 use rustc_hir as hir;
 use rustc_middle::ty::{self, CanonicalUserType, TyCtxt, UserType};
 
-crate trait UserAnnotatedTyHelpers<'tcx> {
+pub(crate) trait UserAnnotatedTyHelpers<'tcx> {
     fn tcx(&self) -> TyCtxt<'tcx>;
 
     fn typeck_results(&self) -> &ty::TypeckResults<'tcx>;
diff --git a/compiler/rustc_mir_dataflow/Cargo.toml b/compiler/rustc_mir_dataflow/Cargo.toml
index ffd7e3c..a0c70a3 100644
--- a/compiler/rustc_mir_dataflow/Cargo.toml
+++ b/compiler/rustc_mir_dataflow/Cargo.toml
@@ -18,6 +18,5 @@
 rustc_index = { path = "../rustc_index" }
 rustc_middle = { path = "../rustc_middle" }
 rustc_serialize = { path = "../rustc_serialize" }
-rustc_session = { path = "../rustc_session" }
 rustc_target = { path = "../rustc_target" }
 rustc_span = { path = "../rustc_span" }
diff --git a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs
index f568121..c0b0cc3 100644
--- a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs
+++ b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs
@@ -410,7 +410,18 @@
     fn open_drop_for_box(&mut self, adt: ty::AdtDef<'tcx>, substs: SubstsRef<'tcx>) -> BasicBlock {
         debug!("open_drop_for_box({:?}, {:?}, {:?})", self, adt, substs);
 
-        let interior = self.tcx().mk_place_deref(self.place);
+        // drop glue is sent straight to codegen
+        // box cannot be directly dereferenced
+        let unique_ty = adt.non_enum_variant().fields[0].ty(self.tcx(), substs);
+        let nonnull_ty =
+            unique_ty.ty_adt_def().unwrap().non_enum_variant().fields[0].ty(self.tcx(), substs);
+        let ptr_ty = self.tcx().mk_imm_ptr(substs[0].expect_ty());
+
+        let unique_place = self.tcx().mk_place_field(self.place, Field::new(0), unique_ty);
+        let nonnull_place = self.tcx().mk_place_field(unique_place, Field::new(0), nonnull_ty);
+        let ptr_place = self.tcx().mk_place_field(nonnull_place, Field::new(0), ptr_ty);
+        let interior = self.tcx().mk_place_deref(ptr_place);
+
         let interior_path = self.elaborator.deref_subpath(self.path);
 
         let succ = self.box_free_block(adt, substs, self.succ, self.unwind);
@@ -625,7 +636,8 @@
                 kind: TerminatorKind::Call {
                     func: Operand::function_handle(tcx, drop_fn, substs, self.source_info.span),
                     args: vec![Operand::Move(Place::from(ref_place))],
-                    destination: Some((unit_temp, succ)),
+                    destination: unit_temp,
+                    target: Some(succ),
                     cleanup: unwind.into_option(),
                     from_hir_call: true,
                     fn_span: self.source_info.span,
@@ -963,7 +975,8 @@
         let call = TerminatorKind::Call {
             func: Operand::function_handle(tcx, free_func, substs, self.source_info.span),
             args,
-            destination: Some((unit_temp, target)),
+            destination: unit_temp,
+            target: Some(target),
             cleanup: None,
             from_hir_call: false,
             fn_span: self.source_info.span,
@@ -1030,7 +1043,7 @@
         Operand::Constant(Box::new(Constant {
             span: self.source_info.span,
             user_ty: None,
-            literal: ty::Const::from_usize(self.tcx(), val.into()).into(),
+            literal: ConstantKind::from_usize(self.tcx(), val.into()),
         }))
     }
 
diff --git a/compiler/rustc_mir_dataflow/src/framework/cursor.rs b/compiler/rustc_mir_dataflow/src/framework/cursor.rs
index 2de5a9d..f3b5544 100644
--- a/compiler/rustc_mir_dataflow/src/framework/cursor.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/cursor.rs
@@ -109,7 +109,7 @@
     /// For backward analyses, this is the state that will be propagated to its
     /// predecessors (ignoring edge-specific effects).
     pub fn seek_to_block_start(&mut self, block: BasicBlock) {
-        if A::Direction::is_forward() {
+        if A::Direction::IS_FORWARD {
             self.seek_to_block_entry(block)
         } else {
             self.seek_after(Location { block, statement_index: 0 }, Effect::Primary)
@@ -123,7 +123,7 @@
     /// For forward analyses, this is the state that will be propagated to its
     /// successors (ignoring edge-specific effects).
     pub fn seek_to_block_end(&mut self, block: BasicBlock) {
-        if A::Direction::is_backward() {
+        if A::Direction::IS_BACKWARD {
             self.seek_to_block_entry(block)
         } else {
             self.seek_after(self.body.terminator_loc(block), Effect::Primary)
@@ -157,7 +157,7 @@
             self.seek_to_block_entry(target.block);
         } else if let Some(curr_effect) = self.pos.curr_effect_index {
             let mut ord = curr_effect.statement_index.cmp(&target.statement_index);
-            if A::Direction::is_backward() {
+            if A::Direction::IS_BACKWARD {
                 ord = ord.reverse()
             }
 
@@ -173,7 +173,7 @@
         debug_assert_eq!(target.block, self.pos.block);
 
         let block_data = &self.body[target.block];
-        let next_effect = if A::Direction::is_forward() {
+        let next_effect = if A::Direction::IS_FORWARD {
             #[rustfmt::skip]
             self.pos.curr_effect_index.map_or_else(
                 || Effect::Before.at_index(0),
diff --git a/compiler/rustc_mir_dataflow/src/framework/direction.rs b/compiler/rustc_mir_dataflow/src/framework/direction.rs
index 1879512..05a4d7b 100644
--- a/compiler/rustc_mir_dataflow/src/framework/direction.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/direction.rs
@@ -9,11 +9,9 @@
 };
 
 pub trait Direction {
-    fn is_forward() -> bool;
+    const IS_FORWARD: bool;
 
-    fn is_backward() -> bool {
-        !Self::is_forward()
-    }
+    const IS_BACKWARD: bool = !Self::IS_FORWARD;
 
     /// Applies all effects between the given `EffectIndex`s.
     ///
@@ -68,9 +66,7 @@
 pub struct Backward;
 
 impl Direction for Backward {
-    fn is_forward() -> bool {
-        false
-    }
+    const IS_FORWARD: bool = false;
 
     fn apply_effects_in_block<'tcx, A>(
         analysis: &A,
@@ -237,14 +233,12 @@
                 // Apply terminator-specific edge effects.
                 //
                 // FIXME(ecstaticmorse): Avoid cloning the exit state unconditionally.
-                mir::TerminatorKind::Call { destination: Some((return_place, dest)), .. }
-                    if dest == bb =>
-                {
+                mir::TerminatorKind::Call { destination, target: Some(dest), .. } if dest == bb => {
                     let mut tmp = exit_state.clone();
                     analysis.apply_call_return_effect(
                         &mut tmp,
                         pred,
-                        CallReturnPlaces::Call(return_place),
+                        CallReturnPlaces::Call(destination),
                     );
                     propagate(pred, &tmp);
                 }
@@ -304,8 +298,8 @@
     }
 }
 
-struct BackwardSwitchIntEdgeEffectsApplier<'a, D, F> {
-    body: &'a mir::Body<'a>,
+struct BackwardSwitchIntEdgeEffectsApplier<'a, 'tcx, D, F> {
+    body: &'a mir::Body<'tcx>,
     pred: BasicBlock,
     exit_state: &'a mut D,
     bb: BasicBlock,
@@ -314,7 +308,7 @@
     effects_applied: bool,
 }
 
-impl<D, F> super::SwitchIntEdgeEffects<D> for BackwardSwitchIntEdgeEffectsApplier<'_, D, F>
+impl<D, F> super::SwitchIntEdgeEffects<D> for BackwardSwitchIntEdgeEffectsApplier<'_, '_, D, F>
 where
     D: Clone,
     F: FnMut(BasicBlock, &D),
@@ -340,9 +334,7 @@
 pub struct Forward;
 
 impl Direction for Forward {
-    fn is_forward() -> bool {
-        true
-    }
+    const IS_FORWARD: bool = true;
 
     fn apply_effects_in_block<'tcx, A>(
         analysis: &A,
@@ -532,20 +524,28 @@
                 propagate(target, exit_state);
             }
 
-            Call { cleanup, destination, func: _, args: _, from_hir_call: _, fn_span: _ } => {
+            Call {
+                cleanup,
+                destination,
+                target,
+                func: _,
+                args: _,
+                from_hir_call: _,
+                fn_span: _,
+            } => {
                 if let Some(unwind) = cleanup {
                     if dead_unwinds.map_or(true, |dead| !dead.contains(bb)) {
                         propagate(unwind, exit_state);
                     }
                 }
 
-                if let Some((dest_place, target)) = destination {
+                if let Some(target) = target {
                     // N.B.: This must be done *last*, otherwise the unwind path will see the call
                     // return effect.
                     analysis.apply_call_return_effect(
                         exit_state,
                         bb,
-                        CallReturnPlaces::Call(dest_place),
+                        CallReturnPlaces::Call(destination),
                     );
                     propagate(target, exit_state);
                 }
diff --git a/compiler/rustc_mir_dataflow/src/framework/engine.rs b/compiler/rustc_mir_dataflow/src/framework/engine.rs
index 50efb4c..20e14a7 100644
--- a/compiler/rustc_mir_dataflow/src/framework/engine.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/engine.rs
@@ -147,7 +147,7 @@
         let mut entry_sets = IndexVec::from_elem(bottom_value.clone(), body.basic_blocks());
         analysis.initialize_start_block(body, &mut entry_sets[mir::START_BLOCK]);
 
-        if A::Direction::is_backward() && entry_sets[mir::START_BLOCK] != bottom_value {
+        if A::Direction::IS_BACKWARD && entry_sets[mir::START_BLOCK] != bottom_value {
             bug!("`initialize_start_block` is not yet supported for backward dataflow analyses");
         }
 
@@ -200,7 +200,7 @@
         let mut dirty_queue: WorkQueue<BasicBlock> =
             WorkQueue::with_none(body.basic_blocks().len());
 
-        if A::Direction::is_forward() {
+        if A::Direction::IS_FORWARD {
             for (bb, _) in traversal::reverse_postorder(body) {
                 dirty_queue.insert(bb);
             }
diff --git a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs
index 599b408..c94198c 100644
--- a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs
@@ -1,7 +1,7 @@
 //! A helpful diagram for debugging dataflow problems.
 
 use std::borrow::Cow;
-use std::lazy::SyncOnceCell;
+use std::sync::OnceLock;
 use std::{io, ops, str};
 
 use regex::Regex;
@@ -125,7 +125,7 @@
     }
 
     fn target(&self, edge: &Self::Edge) -> Self::Node {
-        self.body[edge.source].terminator().successors().nth(edge.index).copied().unwrap()
+        self.body[edge.source].terminator().successors().nth(edge.index).unwrap()
     }
 }
 
@@ -216,9 +216,9 @@
         // Write the full dataflow state immediately after the terminator if it differs from the
         // state at block entry.
         self.results.seek_to_block_end(block);
-        if self.results.get() != &block_start_state || A::Direction::is_backward() {
+        if self.results.get() != &block_start_state || A::Direction::IS_BACKWARD {
             let after_terminator_name = match terminator.kind {
-                mir::TerminatorKind::Call { destination: Some(_), .. } => "(on unwind)",
+                mir::TerminatorKind::Call { target: Some(_), .. } => "(on unwind)",
                 _ => "(on end)",
             };
 
@@ -231,14 +231,14 @@
         // for the basic block itself. That way, we could display terminator-specific effects for
         // backward dataflow analyses as well as effects for `SwitchInt` terminators.
         match terminator.kind {
-            mir::TerminatorKind::Call { destination: Some((return_place, _)), .. } => {
+            mir::TerminatorKind::Call { destination, .. } => {
                 self.write_row(w, "", "(on successful return)", |this, w, fmt| {
                     let state_on_unwind = this.results.get().clone();
                     this.results.apply_custom_effect(|analysis, state| {
                         analysis.apply_call_return_effect(
                             state,
                             block,
-                            CallReturnPlaces::Call(return_place),
+                            CallReturnPlaces::Call(destination),
                         );
                     });
 
@@ -390,7 +390,7 @@
         let mut afters = diffs.after.into_iter();
 
         let next_in_dataflow_order = |it: &mut std::vec::IntoIter<_>| {
-            if A::Direction::is_forward() { it.next().unwrap() } else { it.next_back().unwrap() }
+            if A::Direction::IS_FORWARD { it.next().unwrap() } else { it.next_back().unwrap() }
         };
 
         for (i, statement) in body[block].statements.iter().enumerate() {
@@ -527,7 +527,7 @@
         _block_data: &mir::BasicBlockData<'tcx>,
         _block: BasicBlock,
     ) {
-        if A::Direction::is_forward() {
+        if A::Direction::IS_FORWARD {
             self.prev_state.clone_from(state);
         }
     }
@@ -538,7 +538,7 @@
         _block_data: &mir::BasicBlockData<'tcx>,
         _block: BasicBlock,
     ) {
-        if A::Direction::is_backward() {
+        if A::Direction::IS_BACKWARD {
             self.prev_state.clone_from(state);
         }
     }
@@ -590,7 +590,7 @@
 
 macro_rules! regex {
     ($re:literal $(,)?) => {{
-        static RE: SyncOnceCell<regex::Regex> = SyncOnceCell::new();
+        static RE: OnceLock<regex::Regex> = OnceLock::new();
         RE.get_or_init(|| Regex::new($re).unwrap())
     }};
 }
diff --git a/compiler/rustc_mir_dataflow/src/framework/tests.rs b/compiler/rustc_mir_dataflow/src/framework/tests.rs
index 3cc8d30..d9461fd 100644
--- a/compiler/rustc_mir_dataflow/src/framework/tests.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/tests.rs
@@ -14,7 +14,7 @@
 ///
 /// This is the `Body` that will be used by the `MockAnalysis` below. The shape of its CFG is not
 /// important.
-fn mock_body() -> mir::Body<'static> {
+fn mock_body<'tcx>() -> mir::Body<'tcx> {
     let source_info = mir::SourceInfo::outermost(DUMMY_SP);
 
     let mut blocks = IndexVec::new();
@@ -37,7 +37,8 @@
         mir::TerminatorKind::Call {
             func: mir::Operand::Copy(dummy_place.clone()),
             args: vec![],
-            destination: Some((dummy_place.clone(), mir::START_BLOCK)),
+            destination: dummy_place.clone(),
+            target: Some(mir::START_BLOCK),
             cleanup: None,
             from_hir_call: false,
             fn_span: DUMMY_SP,
@@ -50,7 +51,8 @@
         mir::TerminatorKind::Call {
             func: mir::Operand::Copy(dummy_place.clone()),
             args: vec![],
-            destination: Some((dummy_place.clone(), mir::START_BLOCK)),
+            destination: dummy_place.clone(),
+            target: Some(mir::START_BLOCK),
             cleanup: None,
             from_hir_call: false,
             fn_span: DUMMY_SP,
@@ -138,7 +140,7 @@
             SeekTarget::After(loc) => Effect::Primary.at_index(loc.statement_index),
         };
 
-        let mut pos = if D::is_forward() {
+        let mut pos = if D::IS_FORWARD {
             Effect::Before.at_index(0)
         } else {
             Effect::Before.at_index(self.body[block].statements.len())
@@ -151,7 +153,7 @@
                 return ret;
             }
 
-            if D::is_forward() {
+            if D::IS_FORWARD {
                 pos = pos.next_in_forward_order();
             } else {
                 pos = pos.next_in_backward_order();
diff --git a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs
index 4981ab5..627fe3f 100644
--- a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs
@@ -85,13 +85,7 @@
         self.super_rvalue(rvalue, location);
 
         match rvalue {
-            mir::Rvalue::AddressOf(_mt, borrowed_place) => {
-                if !borrowed_place.is_indirect() {
-                    self.trans.gen(borrowed_place.local);
-                }
-            }
-
-            mir::Rvalue::Ref(_, _kind, borrowed_place) => {
+            mir::Rvalue::AddressOf(_, borrowed_place) | mir::Rvalue::Ref(_, _, borrowed_place) => {
                 if !borrowed_place.is_indirect() {
                     self.trans.gen(borrowed_place.local);
                 }
@@ -145,3 +139,23 @@
         }
     }
 }
+
+/// The set of locals that are borrowed at some point in the MIR body.
+pub fn borrowed_locals(body: &Body<'_>) -> BitSet<Local> {
+    struct Borrowed(BitSet<Local>);
+
+    impl GenKill<Local> for Borrowed {
+        #[inline]
+        fn gen(&mut self, elem: Local) {
+            self.0.gen(elem)
+        }
+        #[inline]
+        fn kill(&mut self, _: Local) {
+            // Ignore borrow invalidation.
+        }
+    }
+
+    let mut borrowed = Borrowed(BitSet::new_empty(body.local_decls.len()));
+    TransferFunction { trans: &mut borrowed }.visit_body(body);
+    borrowed.0
+}
diff --git a/compiler/rustc_mir_dataflow/src/impls/liveness.rs b/compiler/rustc_mir_dataflow/src/impls/liveness.rs
index 5a788c1..35febb5 100644
--- a/compiler/rustc_mir_dataflow/src/impls/liveness.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/liveness.rs
@@ -1,8 +1,8 @@
-use rustc_index::bit_set::BitSet;
+use rustc_index::bit_set::{BitSet, ChunkedBitSet};
 use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor};
-use rustc_middle::mir::{self, Local, Location};
+use rustc_middle::mir::{self, Local, Location, Place, StatementKind};
 
-use crate::{AnalysisDomain, Backward, CallReturnPlaces, GenKill, GenKillAnalysis};
+use crate::{Analysis, AnalysisDomain, Backward, CallReturnPlaces, GenKill, GenKillAnalysis};
 
 /// A [live-variable dataflow analysis][liveness].
 ///
@@ -30,14 +30,14 @@
 }
 
 impl<'tcx> AnalysisDomain<'tcx> for MaybeLiveLocals {
-    type Domain = BitSet<Local>;
+    type Domain = ChunkedBitSet<Local>;
     type Direction = Backward;
 
     const NAME: &'static str = "liveness";
 
     fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain {
         // bottom = not live
-        BitSet::new_empty(body.local_decls.len())
+        ChunkedBitSet::new_empty(body.local_decls.len())
     }
 
     fn initialize_start_block(&self, _: &mir::Body<'tcx>, _: &mut Self::Domain) {
@@ -98,19 +98,16 @@
     T: GenKill<Local>,
 {
     fn visit_place(&mut self, place: &mir::Place<'tcx>, context: PlaceContext, location: Location) {
-        let mir::Place { projection, local } = *place;
+        let local = place.local;
 
         // We purposefully do not call `super_place` here to avoid calling `visit_local` for this
         // place with one of the `Projection` variants of `PlaceContext`.
         self.visit_projection(place.as_ref(), context, location);
 
-        match DefUse::for_place(context) {
-            // Treat derefs as a use of the base local. `*p = 4` is not a def of `p` but a use.
-            Some(_) if place.is_indirect() => self.0.gen(local),
-
-            Some(DefUse::Def) if projection.is_empty() => self.0.kill(local),
+        match DefUse::for_place(*place, context) {
+            Some(DefUse::Def) => self.0.kill(local),
             Some(DefUse::Use) => self.0.gen(local),
-            _ => {}
+            None => {}
         }
     }
 
@@ -118,10 +115,10 @@
         // Because we do not call `super_place` above, `visit_local` is only called for locals that
         // do not appear as part of  a `Place` in the MIR. This handles cases like the implicit use
         // of the return place in a `Return` terminator or the index in an `Index` projection.
-        match DefUse::for_place(context) {
+        match DefUse::for_place(local.into(), context) {
             Some(DefUse::Def) => self.0.kill(local),
             Some(DefUse::Use) => self.0.gen(local),
-            _ => {}
+            None => {}
         }
     }
 }
@@ -133,27 +130,37 @@
 }
 
 impl DefUse {
-    fn for_place(context: PlaceContext) -> Option<DefUse> {
+    fn for_place<'tcx>(place: Place<'tcx>, context: PlaceContext) -> Option<DefUse> {
         match context {
             PlaceContext::NonUse(_) => None,
 
             PlaceContext::MutatingUse(MutatingUseContext::Store | MutatingUseContext::Deinit) => {
-                Some(DefUse::Def)
+                if place.is_indirect() {
+                    // Treat derefs as a use of the base local. `*p = 4` is not a def of `p` but a
+                    // use.
+                    Some(DefUse::Use)
+                } else if place.projection.is_empty() {
+                    Some(DefUse::Def)
+                } else {
+                    None
+                }
             }
 
             // Setting the discriminant is not a use because it does no reading, but it is also not
             // a def because it does not overwrite the whole place
-            PlaceContext::MutatingUse(MutatingUseContext::SetDiscriminant) => None,
+            PlaceContext::MutatingUse(MutatingUseContext::SetDiscriminant) => {
+                place.is_indirect().then_some(DefUse::Use)
+            }
 
-            // `MutatingUseContext::Call` and `MutatingUseContext::Yield` indicate that this is the
-            // destination place for a `Call` return or `Yield` resume respectively. Since this is
-            // only a `Def` when the function returns successfully, we handle this case separately
-            // in `call_return_effect` above.
+            // For the associated terminators, this is only a `Def` when the terminator returns
+            // "successfully." As such, we handle this case separately in `call_return_effect`
+            // above. However, if the place looks like `*_5`, this is still unconditionally a use of
+            // `_5`.
             PlaceContext::MutatingUse(
                 MutatingUseContext::Call
-                | MutatingUseContext::AsmOutput
-                | MutatingUseContext::Yield,
-            ) => None,
+                | MutatingUseContext::Yield
+                | MutatingUseContext::AsmOutput,
+            ) => place.is_indirect().then_some(DefUse::Use),
 
             // All other contexts are uses...
             PlaceContext::MutatingUse(
@@ -179,3 +186,124 @@
         }
     }
 }
+
+/// Like `MaybeLiveLocals`, but does not mark locals as live if they are used in a dead assignment.
+///
+/// This is basically written for dead store elimination and nothing else.
+///
+/// All of the caveats of `MaybeLiveLocals` apply.
+pub struct MaybeTransitiveLiveLocals<'a> {
+    always_live: &'a BitSet<Local>,
+}
+
+impl<'a> MaybeTransitiveLiveLocals<'a> {
+    /// The `always_alive` set is the set of locals to which all stores should unconditionally be
+    /// considered live.
+    ///
+    /// This should include at least all locals that are ever borrowed.
+    pub fn new(always_live: &'a BitSet<Local>) -> Self {
+        MaybeTransitiveLiveLocals { always_live }
+    }
+}
+
+impl<'a, 'tcx> AnalysisDomain<'tcx> for MaybeTransitiveLiveLocals<'a> {
+    type Domain = ChunkedBitSet<Local>;
+    type Direction = Backward;
+
+    const NAME: &'static str = "transitive liveness";
+
+    fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain {
+        // bottom = not live
+        ChunkedBitSet::new_empty(body.local_decls.len())
+    }
+
+    fn initialize_start_block(&self, _: &mir::Body<'tcx>, _: &mut Self::Domain) {
+        // No variables are live until we observe a use
+    }
+}
+
+struct TransferWrapper<'a>(&'a mut ChunkedBitSet<Local>);
+
+impl<'a> GenKill<Local> for TransferWrapper<'a> {
+    fn gen(&mut self, l: Local) {
+        self.0.insert(l);
+    }
+
+    fn kill(&mut self, l: Local) {
+        self.0.remove(l);
+    }
+}
+
+impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> {
+    fn apply_statement_effect(
+        &self,
+        trans: &mut Self::Domain,
+        statement: &mir::Statement<'tcx>,
+        location: Location,
+    ) {
+        // Compute the place that we are storing to, if any
+        let destination = match &statement.kind {
+            StatementKind::Assign(assign) => {
+                if assign.1.is_safe_to_remove() {
+                    Some(assign.0)
+                } else {
+                    None
+                }
+            }
+            StatementKind::SetDiscriminant { place, .. } | StatementKind::Deinit(place) => {
+                Some(**place)
+            }
+            StatementKind::FakeRead(_)
+            | StatementKind::StorageLive(_)
+            | StatementKind::StorageDead(_)
+            | StatementKind::Retag(..)
+            | StatementKind::AscribeUserType(..)
+            | StatementKind::Coverage(..)
+            | StatementKind::CopyNonOverlapping(..)
+            | StatementKind::Nop => None,
+        };
+        if let Some(destination) = destination {
+            if !destination.is_indirect()
+                && !trans.contains(destination.local)
+                && !self.always_live.contains(destination.local)
+            {
+                // This store is dead
+                return;
+            }
+        }
+        TransferFunction(&mut TransferWrapper(trans)).visit_statement(statement, location);
+    }
+
+    fn apply_terminator_effect(
+        &self,
+        trans: &mut Self::Domain,
+        terminator: &mir::Terminator<'tcx>,
+        location: Location,
+    ) {
+        TransferFunction(&mut TransferWrapper(trans)).visit_terminator(terminator, location);
+    }
+
+    fn apply_call_return_effect(
+        &self,
+        trans: &mut Self::Domain,
+        _block: mir::BasicBlock,
+        return_places: CallReturnPlaces<'_, 'tcx>,
+    ) {
+        return_places.for_each(|place| {
+            if let Some(local) = place.as_local() {
+                trans.remove(local);
+            }
+        });
+    }
+
+    fn apply_yield_resume_effect(
+        &self,
+        trans: &mut Self::Domain,
+        _resume_block: mir::BasicBlock,
+        resume_place: mir::Place<'tcx>,
+    ) {
+        if let Some(local) = resume_place.as_local() {
+            trans.remove(local);
+        }
+    }
+}
diff --git a/compiler/rustc_mir_dataflow/src/impls/mod.rs b/compiler/rustc_mir_dataflow/src/impls/mod.rs
index c9722a6..af6a1bb1 100644
--- a/compiler/rustc_mir_dataflow/src/impls/mod.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/mod.rs
@@ -23,9 +23,11 @@
 mod liveness;
 mod storage_liveness;
 
+pub use self::borrowed_locals::borrowed_locals;
 pub use self::borrowed_locals::MaybeBorrowedLocals;
 pub use self::init_locals::MaybeInitializedLocals;
 pub use self::liveness::MaybeLiveLocals;
+pub use self::liveness::MaybeTransitiveLiveLocals;
 pub use self::storage_liveness::{MaybeRequiresStorage, MaybeStorageLive};
 
 /// `MaybeInitializedPlaces` tracks all places that might be
diff --git a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs
index 2730e8bd..33d2941 100644
--- a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs
@@ -1,6 +1,5 @@
 pub use super::*;
 
-use crate::storage::AlwaysLiveLocals;
 use crate::{CallReturnPlaces, GenKill, Results, ResultsRefCursor};
 use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor};
 use rustc_middle::mir::*;
@@ -8,11 +7,11 @@
 
 #[derive(Clone)]
 pub struct MaybeStorageLive {
-    always_live_locals: AlwaysLiveLocals,
+    always_live_locals: BitSet<Local>,
 }
 
 impl MaybeStorageLive {
-    pub fn new(always_live_locals: AlwaysLiveLocals) -> Self {
+    pub fn new(always_live_locals: BitSet<Local>) -> Self {
         MaybeStorageLive { always_live_locals }
     }
 }
@@ -169,8 +168,8 @@
         self.borrowed_locals.borrow().analysis().terminator_effect(trans, terminator, loc);
 
         match &terminator.kind {
-            TerminatorKind::Call { destination: Some((place, _)), .. } => {
-                trans.gen(place.local);
+            TerminatorKind::Call { destination, .. } => {
+                trans.gen(destination.local);
             }
 
             // Note that we do *not* gen the `resume_arg` of `Yield` terminators. The reason for
@@ -198,8 +197,7 @@
 
             // Nothing to do for these. Match exhaustively so this fails to compile when new
             // variants are added.
-            TerminatorKind::Call { destination: None, .. }
-            | TerminatorKind::Abort
+            TerminatorKind::Abort
             | TerminatorKind::Assert { .. }
             | TerminatorKind::Drop { .. }
             | TerminatorKind::DropAndReplace { .. }
@@ -225,8 +223,8 @@
             // 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);
+            TerminatorKind::Call { destination, .. } => {
+                trans.kill(destination.local);
             }
 
             // The same applies to InlineAsm outputs.
@@ -236,8 +234,7 @@
 
             // Nothing to do for these. Match exhaustively so this fails to compile when new
             // variants are added.
-            TerminatorKind::Call { destination: None, .. }
-            | TerminatorKind::Yield { .. }
+            TerminatorKind::Yield { .. }
             | TerminatorKind::Abort
             | TerminatorKind::Assert { .. }
             | TerminatorKind::Drop { .. }
diff --git a/compiler/rustc_mir_dataflow/src/lib.rs b/compiler/rustc_mir_dataflow/src/lib.rs
index c1124a5..e4c130f 100644
--- a/compiler/rustc_mir_dataflow/src/lib.rs
+++ b/compiler/rustc_mir_dataflow/src/lib.rs
@@ -1,6 +1,5 @@
 #![feature(associated_type_defaults)]
 #![feature(box_patterns)]
-#![feature(box_syntax)]
 #![feature(exact_size_is_empty)]
 #![feature(let_else)]
 #![feature(min_specialization)]
diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
index 7307246..b08cb50 100644
--- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
+++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
@@ -376,7 +376,8 @@
             TerminatorKind::Call {
                 ref func,
                 ref args,
-                ref destination,
+                destination,
+                target,
                 cleanup: _,
                 from_hir_call: _,
                 fn_span: _,
@@ -385,7 +386,7 @@
                 for arg in args {
                     self.gather_operand(arg);
                 }
-                if let Some((destination, _bb)) = *destination {
+                if let Some(_bb) = target {
                     self.create_move_path(destination);
                     self.gather_init(destination.as_ref(), InitKind::NonPanicPathOnly);
                 }
diff --git a/compiler/rustc_mir_dataflow/src/rustc_peek.rs b/compiler/rustc_mir_dataflow/src/rustc_peek.rs
index cc9ee10..e1df482 100644
--- a/compiler/rustc_mir_dataflow/src/rustc_peek.rs
+++ b/compiler/rustc_mir_dataflow/src/rustc_peek.rs
@@ -1,8 +1,7 @@
 use rustc_span::symbol::sym;
 use rustc_span::Span;
-use rustc_target::spec::abi::Abi;
 
-use rustc_index::bit_set::BitSet;
+use rustc_index::bit_set::ChunkedBitSet;
 use rustc_middle::mir::MirPass;
 use rustc_middle::mir::{self, Body, Local, Location};
 use rustc_middle::ty::{self, Ty, TyCtxt};
@@ -193,9 +192,8 @@
             &terminator.kind
         {
             if let ty::FnDef(def_id, substs) = *func.literal.ty().kind() {
-                let sig = tcx.fn_sig(def_id);
                 let name = tcx.item_name(def_id);
-                if sig.abi() != Abi::RustIntrinsic || name != sym::rustc_peek {
+                if !tcx.is_intrinsic(def_id) || name != sym::rustc_peek {
                     return None;
                 }
 
@@ -273,7 +271,7 @@
         &self,
         tcx: TyCtxt<'tcx>,
         place: mir::Place<'tcx>,
-        flow_state: &BitSet<Local>,
+        flow_state: &ChunkedBitSet<Local>,
         call: PeekCall,
     ) {
         info!(?place, "peek_at");
diff --git a/compiler/rustc_mir_dataflow/src/storage.rs b/compiler/rustc_mir_dataflow/src/storage.rs
index 218d455..4a354c4 100644
--- a/compiler/rustc_mir_dataflow/src/storage.rs
+++ b/compiler/rustc_mir_dataflow/src/storage.rs
@@ -7,35 +7,17 @@
 //
 // FIXME: Currently, we need to traverse the entire MIR to compute this. We should instead store it
 // as a field in the `LocalDecl` for each `Local`.
-#[derive(Debug, Clone)]
-pub struct AlwaysLiveLocals(BitSet<Local>);
+pub fn always_live_locals(body: &mir::Body<'_>) -> BitSet<Local> {
+    let mut always_live_locals = BitSet::new_filled(body.local_decls.len());
 
-impl AlwaysLiveLocals {
-    pub fn new(body: &mir::Body<'_>) -> Self {
-        let mut always_live_locals = AlwaysLiveLocals(BitSet::new_filled(body.local_decls.len()));
-
-        for block in body.basic_blocks() {
-            for statement in &block.statements {
-                use mir::StatementKind::{StorageDead, StorageLive};
-                if let StorageLive(l) | StorageDead(l) = statement.kind {
-                    always_live_locals.0.remove(l);
-                }
+    for block in body.basic_blocks() {
+        for statement in &block.statements {
+            use mir::StatementKind::{StorageDead, StorageLive};
+            if let StorageLive(l) | StorageDead(l) = statement.kind {
+                always_live_locals.remove(l);
             }
         }
-
-        always_live_locals
     }
 
-    pub fn into_inner(self) -> BitSet<Local> {
-        self.0
-    }
-}
-
-impl std::ops::Deref for AlwaysLiveLocals {
-    type Target = BitSet<Local>;
-
-    #[inline]
-    fn deref(&self) -> &Self::Target {
-        &self.0
-    }
+    always_live_locals
 }
diff --git a/compiler/rustc_mir_transform/Cargo.toml b/compiler/rustc_mir_transform/Cargo.toml
index 4c1a7ea..8a8098e 100644
--- a/compiler/rustc_mir_transform/Cargo.toml
+++ b/compiler/rustc_mir_transform/Cargo.toml
@@ -19,7 +19,6 @@
 rustc_middle = { path = "../rustc_middle" }
 rustc_const_eval = { path = "../rustc_const_eval" }
 rustc_mir_dataflow = { path = "../rustc_mir_dataflow" }
-rustc_query_system = { path = "../rustc_query_system" }
 rustc_serialize = { path = "../rustc_serialize" }
 rustc_session = { path = "../rustc_session" }
 rustc_target = { path = "../rustc_target" }
diff --git a/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs b/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs
index ade6555..1198038 100644
--- a/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs
+++ b/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs
@@ -1,4 +1,5 @@
 use crate::MirPass;
+use rustc_ast::InlineAsmOptions;
 use rustc_hir::def::DefKind;
 use rustc_middle::mir::*;
 use rustc_middle::ty::layout;
@@ -85,6 +86,12 @@
                 TerminatorKind::Assert { .. } | TerminatorKind::FalseUnwind { .. } => {
                     layout::fn_can_unwind(tcx, None, Abi::Rust)
                 }
+                TerminatorKind::InlineAsm { options, .. } => {
+                    options.contains(InlineAsmOptions::MAY_UNWIND)
+                }
+                _ if terminator.unwind().is_some() => {
+                    span_bug!(span, "unexpected terminator that may unwind {:?}", terminator)
+                }
                 _ => continue,
             };
 
diff --git a/compiler/rustc_mir_transform/src/add_call_guards.rs b/compiler/rustc_mir_transform/src/add_call_guards.rs
index cd6b671..10d5227 100644
--- a/compiler/rustc_mir_transform/src/add_call_guards.rs
+++ b/compiler/rustc_mir_transform/src/add_call_guards.rs
@@ -50,12 +50,7 @@
         for block in body.basic_blocks_mut() {
             match block.terminator {
                 Some(Terminator {
-                    kind:
-                        TerminatorKind::Call {
-                            destination: Some((_, ref mut destination)),
-                            cleanup,
-                            ..
-                        },
+                    kind: TerminatorKind::Call { target: Some(ref mut destination), cleanup, .. },
                     source_info,
                 }) if pred_count[*destination] > 1
                     && (cleanup.is_some() || self == &AllCallEdges) =>
diff --git a/compiler/rustc_mir_transform/src/add_retag.rs b/compiler/rustc_mir_transform/src/add_retag.rs
index a245da6..0495439 100644
--- a/compiler/rustc_mir_transform/src/add_retag.rs
+++ b/compiler/rustc_mir_transform/src/add_retag.rs
@@ -130,11 +130,11 @@
             .iter_mut()
             .filter_map(|block_data| {
                 match block_data.terminator().kind {
-                    TerminatorKind::Call { destination: Some(ref destination), .. }
-                        if needs_retag(&destination.0) =>
+                    TerminatorKind::Call { target: Some(target), destination, .. }
+                        if needs_retag(&destination) =>
                     {
                         // Remember the return destination for later
-                        Some((block_data.terminator().source_info, destination.0, destination.1))
+                        Some((block_data.terminator().source_info, destination, target))
                     }
 
                     // `Drop` is also a call, but it doesn't return anything so we are good.
diff --git a/compiler/rustc_mir_transform/src/const_debuginfo.rs b/compiler/rustc_mir_transform/src/const_debuginfo.rs
index 3577b3d..8944ebe 100644
--- a/compiler/rustc_mir_transform/src/const_debuginfo.rs
+++ b/compiler/rustc_mir_transform/src/const_debuginfo.rs
@@ -19,7 +19,7 @@
         sess.opts.debugging_opts.unsound_mir_opts && sess.mir_opt_level() > 0
     }
 
-    fn run_pass(&self, _: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+    fn run_pass(&self, _tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         trace!("running ConstDebugInfo on {:?}", body.source);
 
         for (local, constant) in find_optimization_oportunities(body) {
diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs
index 54c3cc4..412a5b4 100644
--- a/compiler/rustc_mir_transform/src/const_prop.rs
+++ b/compiler/rustc_mir_transform/src/const_prop.rs
@@ -67,6 +67,7 @@
         true
     }
 
+    #[instrument(skip(self, tcx), level = "debug")]
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         // will be evaluated by miri and produce its errors there
         if body.source.promoted.is_some() {
@@ -200,7 +201,8 @@
         _instance: ty::Instance<'tcx>,
         _abi: Abi,
         _args: &[OpTy<'tcx>],
-        _ret: Option<(&PlaceTy<'tcx>, BasicBlock)>,
+        _destination: &PlaceTy<'tcx>,
+        _target: Option<BasicBlock>,
         _unwind: StackPopUnwind,
     ) -> InterpResult<'tcx, Option<(&'mir Body<'tcx>, ty::Instance<'tcx>)>> {
         Ok(None)
@@ -210,7 +212,8 @@
         _ecx: &mut InterpCx<'mir, 'tcx, Self>,
         _instance: ty::Instance<'tcx>,
         _args: &[OpTy<'tcx>],
-        _ret: Option<(&PlaceTy<'tcx>, BasicBlock)>,
+        _destination: &PlaceTy<'tcx>,
+        _target: Option<BasicBlock>,
         _unwind: StackPopUnwind,
     ) -> InterpResult<'tcx> {
         throw_machine_stop_str!("calling intrinsics isn't supported in ConstProp")
@@ -384,24 +387,22 @@
             ConstPropMachine::new(only_propagate_inside_block_locals, can_const_prop),
         );
 
-        let ret = ecx
+        let ret_layout = ecx
             .layout_of(EarlyBinder(body.return_ty()).subst(tcx, substs))
             .ok()
-            // Don't bother allocating memory for ZST types which have no values
-            // or for large values.
-            .filter(|ret_layout| {
-                !ret_layout.is_zst() && ret_layout.size < Size::from_bytes(MAX_ALLOC_LIMIT)
-            })
-            .map(|ret_layout| {
-                ecx.allocate(ret_layout, MemoryKind::Stack)
-                    .expect("couldn't perform small allocation")
-                    .into()
-            });
+            // Don't bother allocating memory for large values.
+            .filter(|ret_layout| ret_layout.size < Size::from_bytes(MAX_ALLOC_LIMIT))
+            .unwrap_or_else(|| ecx.layout_of(tcx.types.unit).unwrap());
+
+        let ret = ecx
+            .allocate(ret_layout, MemoryKind::Stack)
+            .expect("couldn't perform small allocation")
+            .into();
 
         ecx.push_stack_frame(
             Instance::new(def_id, substs),
             dummy_body,
-            ret.as_ref(),
+            &ret,
             StackPopCleanup::Root { cleanup: false },
         )
         .expect("failed to push initial stack frame");
@@ -687,7 +688,7 @@
         Operand::Constant(Box::new(Constant {
             span,
             user_ty: None,
-            literal: ty::Const::from_scalar(self.tcx, scalar, ty).into(),
+            literal: ConstantKind::from_scalar(self.tcx, scalar, ty),
         }))
     }
 
@@ -699,7 +700,7 @@
     ) {
         if let Rvalue::Use(Operand::Constant(c)) = rval {
             match c.literal {
-                ConstantKind::Ty(c) if matches!(c.val(), ConstKind::Unevaluated(..)) => {}
+                ConstantKind::Ty(c) if matches!(c.kind(), ConstKind::Unevaluated(..)) => {}
                 _ => {
                     trace!("skipping replace of Rvalue::Use({:?} because it is already a const", c);
                     return;
@@ -765,20 +766,12 @@
                             if let Some(Some(alloc)) = alloc {
                                 // Assign entire constant in a single statement.
                                 // We can't use aggregates, as we run after the aggregate-lowering `MirPhase`.
+                                let const_val = ConstValue::ByRef { alloc, offset: Size::ZERO };
+                                let literal = ConstantKind::Val(const_val, ty);
                                 *rval = Rvalue::Use(Operand::Constant(Box::new(Constant {
                                     span: source_info.span,
                                     user_ty: None,
-                                    literal: self
-                                        .ecx
-                                        .tcx
-                                        .mk_const(ty::ConstS {
-                                            ty,
-                                            val: ty::ConstKind::Value(ConstValue::ByRef {
-                                                alloc,
-                                                offset: Size::ZERO,
-                                            }),
-                                        })
-                                        .into(),
+                                    literal,
                                 })));
                             }
                         }
diff --git a/compiler/rustc_mir_transform/src/const_prop_lint.rs b/compiler/rustc_mir_transform/src/const_prop_lint.rs
index 6c0df98..15ad130 100644
--- a/compiler/rustc_mir_transform/src/const_prop_lint.rs
+++ b/compiler/rustc_mir_transform/src/const_prop_lint.rs
@@ -192,7 +192,8 @@
         _instance: ty::Instance<'tcx>,
         _abi: Abi,
         _args: &[OpTy<'tcx>],
-        _ret: Option<(&PlaceTy<'tcx>, BasicBlock)>,
+        _destination: &PlaceTy<'tcx>,
+        _target: Option<BasicBlock>,
         _unwind: StackPopUnwind,
     ) -> InterpResult<'tcx, Option<(&'mir Body<'tcx>, ty::Instance<'tcx>)>> {
         Ok(None)
@@ -202,7 +203,8 @@
         _ecx: &mut InterpCx<'mir, 'tcx, Self>,
         _instance: ty::Instance<'tcx>,
         _args: &[OpTy<'tcx>],
-        _ret: Option<(&PlaceTy<'tcx>, BasicBlock)>,
+        _destination: &PlaceTy<'tcx>,
+        _target: Option<BasicBlock>,
         _unwind: StackPopUnwind,
     ) -> InterpResult<'tcx> {
         throw_machine_stop_str!("calling intrinsics isn't supported in ConstProp")
@@ -377,24 +379,22 @@
             ConstPropMachine::new(only_propagate_inside_block_locals, can_const_prop),
         );
 
-        let ret = ecx
+        let ret_layout = ecx
             .layout_of(EarlyBinder(body.return_ty()).subst(tcx, substs))
             .ok()
-            // Don't bother allocating memory for ZST types which have no values
-            // or for large values.
-            .filter(|ret_layout| {
-                !ret_layout.is_zst() && ret_layout.size < Size::from_bytes(MAX_ALLOC_LIMIT)
-            })
-            .map(|ret_layout| {
-                ecx.allocate(ret_layout, MemoryKind::Stack)
-                    .expect("couldn't perform small allocation")
-                    .into()
-            });
+            // Don't bother allocating memory for large values.
+            .filter(|ret_layout| ret_layout.size < Size::from_bytes(MAX_ALLOC_LIMIT))
+            .unwrap_or_else(|| ecx.layout_of(tcx.types.unit).unwrap());
+
+        let ret = ecx
+            .allocate(ret_layout, MemoryKind::Stack)
+            .expect("couldn't perform small allocation")
+            .into();
 
         ecx.push_stack_frame(
             Instance::new(def_id, substs),
             dummy_body,
-            ret.as_ref(),
+            &ret,
             StackPopCleanup::Root { cleanup: false },
         )
         .expect("failed to push initial stack frame");
@@ -437,10 +437,12 @@
         source_info.scope.lint_root(self.source_scopes)
     }
 
-    fn use_ecx<F, T>(&mut self, f: F) -> Option<T>
+    fn use_ecx<F, T>(&mut self, source_info: SourceInfo, f: F) -> Option<T>
     where
         F: FnOnce(&mut Self) -> InterpResult<'tcx, T>,
     {
+        // Overwrite the PC -- whatever the interpreter does to it does not make any sense anyway.
+        self.ecx.frame_mut().loc = Err(source_info.span);
         match f(self) {
             Ok(val) => Some(val),
             Err(error) => {
@@ -472,7 +474,7 @@
                 let err = ConstEvalErr::new(&self.ecx, error, Some(c.span));
                 if let Some(lint_root) = self.lint_root(source_info) {
                     let lint_only = match c.literal {
-                        ConstantKind::Ty(ct) => match ct.val() {
+                        ConstantKind::Ty(ct) => match ct.kind() {
                             // Promoteds must lint and not error as the user didn't ask for them
                             ConstKind::Unevaluated(ty::Unevaluated {
                                 def: _,
@@ -501,9 +503,9 @@
     }
 
     /// Returns the value, if any, of evaluating `place`.
-    fn eval_place(&mut self, place: Place<'tcx>) -> Option<OpTy<'tcx>> {
+    fn eval_place(&mut self, place: Place<'tcx>, source_info: SourceInfo) -> Option<OpTy<'tcx>> {
         trace!("eval_place(place={:?})", place);
-        self.use_ecx(|this| this.ecx.eval_place_to_op(place, None))
+        self.use_ecx(source_info, |this| this.ecx.eval_place_to_op(place, None))
     }
 
     /// Returns the value, if any, of evaluating `op`. Calls upon `eval_constant`
@@ -511,7 +513,7 @@
     fn eval_operand(&mut self, op: &Operand<'tcx>, source_info: SourceInfo) -> Option<OpTy<'tcx>> {
         match *op {
             Operand::Constant(ref c) => self.eval_constant(c, source_info),
-            Operand::Move(place) | Operand::Copy(place) => self.eval_place(place),
+            Operand::Move(place) | Operand::Copy(place) => self.eval_place(place, source_info),
         }
     }
 
@@ -537,7 +539,7 @@
         arg: &Operand<'tcx>,
         source_info: SourceInfo,
     ) -> Option<()> {
-        if let (val, true) = self.use_ecx(|this| {
+        if let (val, true) = self.use_ecx(source_info, |this| {
             let val = this.ecx.read_immediate(&this.ecx.eval_operand(arg, None)?)?;
             let (_res, overflow, _ty) = this.ecx.overflowing_unary_op(op, &val)?;
             Ok((val, overflow))
@@ -564,8 +566,12 @@
         right: &Operand<'tcx>,
         source_info: SourceInfo,
     ) -> Option<()> {
-        let r = self.use_ecx(|this| this.ecx.read_immediate(&this.ecx.eval_operand(right, None)?));
-        let l = self.use_ecx(|this| this.ecx.read_immediate(&this.ecx.eval_operand(left, None)?));
+        let r = self.use_ecx(source_info, |this| {
+            this.ecx.read_immediate(&this.ecx.eval_operand(right, None)?)
+        });
+        let l = self.use_ecx(source_info, |this| {
+            this.ecx.read_immediate(&this.ecx.eval_operand(left, None)?)
+        });
         // Check for exceeding shifts *even if* we cannot evaluate the LHS.
         if op == BinOp::Shr || op == BinOp::Shl {
             let r = r?;
@@ -602,7 +608,7 @@
 
         if let (Some(l), Some(r)) = (&l, &r) {
             // The remaining operators are handled through `overflowing_binary_op`.
-            if self.use_ecx(|this| {
+            if self.use_ecx(source_info, |this| {
                 let (_res, overflow, _ty) = this.ecx.overflowing_binary_op(op, l, r)?;
                 Ok(overflow)
             })? {
@@ -690,7 +696,7 @@
             return None;
         }
 
-        self.use_ecx(|this| this.ecx.eval_rvalue_into_place(rvalue, place))
+        self.use_ecx(source_info, |this| this.ecx.eval_rvalue_into_place(rvalue, place))
     }
 }
 
@@ -890,7 +896,10 @@
                 StatementKind::SetDiscriminant { ref place, .. } => {
                     match self.ecx.machine.can_const_prop[place.local] {
                         ConstPropMode::FullConstProp | ConstPropMode::OnlyInsideOwnBlock => {
-                            if self.use_ecx(|this| this.ecx.statement(statement)).is_some() {
+                            if self
+                                .use_ecx(source_info, |this| this.ecx.statement(statement))
+                                .is_some()
+                            {
                                 trace!("propped discriminant into {:?}", place);
                             } else {
                                 Self::remove_const(&mut self.ecx, place.local);
diff --git a/compiler/rustc_mir_transform/src/coverage/counters.rs b/compiler/rustc_mir_transform/src/coverage/counters.rs
index 6726b66..45de0c2 100644
--- a/compiler/rustc_mir_transform/src/coverage/counters.rs
+++ b/compiler/rustc_mir_transform/src/coverage/counters.rs
@@ -43,7 +43,7 @@
     pub fn make_bcb_counters(
         &mut self,
         basic_coverage_blocks: &mut CoverageGraph,
-        coverage_spans: &Vec<CoverageSpan>,
+        coverage_spans: &[CoverageSpan],
     ) -> Result<Vec<CoverageKind>, Error> {
         let mut bcb_counters = BcbCounters::new(self, basic_coverage_blocks);
         bcb_counters.make_bcb_counters(coverage_spans)
@@ -349,7 +349,7 @@
         // counters and/or expressions of its incoming edges. This will recursively get or create
         // counters for those incoming edges first, then call `make_expression()` to sum them up,
         // with additional intermediate expressions as needed.
-        let mut predecessors = self.bcb_predecessors(bcb).clone().into_iter();
+        let mut predecessors = self.bcb_predecessors(bcb).to_owned().into_iter();
         debug!(
             "{}{:?} has multiple incoming edges and will get an expression that sums them up...",
             NESTED_INDENT.repeat(debug_indent_level),
@@ -571,12 +571,12 @@
     }
 
     #[inline]
-    fn bcb_predecessors(&self, bcb: BasicCoverageBlock) -> &Vec<BasicCoverageBlock> {
+    fn bcb_predecessors(&self, bcb: BasicCoverageBlock) -> &[BasicCoverageBlock] {
         &self.basic_coverage_blocks.predecessors[bcb]
     }
 
     #[inline]
-    fn bcb_successors(&self, bcb: BasicCoverageBlock) -> &Vec<BasicCoverageBlock> {
+    fn bcb_successors(&self, bcb: BasicCoverageBlock) -> &[BasicCoverageBlock] {
         &self.basic_coverage_blocks.successors[bcb]
     }
 
diff --git a/compiler/rustc_mir_transform/src/coverage/debug.rs b/compiler/rustc_mir_transform/src/coverage/debug.rs
index 8e28ed2..0f8679b 100644
--- a/compiler/rustc_mir_transform/src/coverage/debug.rs
+++ b/compiler/rustc_mir_transform/src/coverage/debug.rs
@@ -123,14 +123,15 @@
 use rustc_span::Span;
 
 use std::iter;
-use std::lazy::SyncOnceCell;
+use std::ops::Deref;
+use std::sync::OnceLock;
 
 pub const NESTED_INDENT: &str = "    ";
 
 const RUSTC_COVERAGE_DEBUG_OPTIONS: &str = "RUSTC_COVERAGE_DEBUG_OPTIONS";
 
 pub(super) fn debug_options<'a>() -> &'a DebugOptions {
-    static DEBUG_OPTIONS: SyncOnceCell<DebugOptions> = SyncOnceCell::new();
+    static DEBUG_OPTIONS: OnceLock<DebugOptions> = OnceLock::new();
 
     &DEBUG_OPTIONS.get_or_init(DebugOptions::from_env)
 }
@@ -434,11 +435,11 @@
     pub fn get_bcb_coverage_spans_with_counters(
         &self,
         bcb: BasicCoverageBlock,
-    ) -> Option<&Vec<(CoverageSpan, CoverageKind)>> {
+    ) -> Option<&[(CoverageSpan, CoverageKind)]> {
         if let Some(bcb_to_coverage_spans_with_counters) =
             self.some_bcb_to_coverage_spans_with_counters.as_ref()
         {
-            bcb_to_coverage_spans_with_counters.get(&bcb)
+            bcb_to_coverage_spans_with_counters.get(&bcb).map(Deref::deref)
         } else {
             None
         }
@@ -457,12 +458,9 @@
         }
     }
 
-    pub fn get_bcb_dependency_counters(
-        &self,
-        bcb: BasicCoverageBlock,
-    ) -> Option<&Vec<CoverageKind>> {
+    pub fn get_bcb_dependency_counters(&self, bcb: BasicCoverageBlock) -> Option<&[CoverageKind]> {
         if let Some(bcb_to_dependency_counters) = self.some_bcb_to_dependency_counters.as_ref() {
-            bcb_to_dependency_counters.get(&bcb)
+            bcb_to_dependency_counters.get(&bcb).map(Deref::deref)
         } else {
             None
         }
@@ -571,11 +569,11 @@
     /// associated with a coverage span).
     pub fn validate(
         &mut self,
-        bcb_counters_without_direct_coverage_spans: &Vec<(
+        bcb_counters_without_direct_coverage_spans: &[(
             Option<BasicCoverageBlock>,
             BasicCoverageBlock,
             CoverageKind,
-        )>,
+        )],
     ) {
         if self.is_enabled() {
             let mut not_validated = bcb_counters_without_direct_coverage_spans
@@ -634,7 +632,7 @@
     basic_coverage_blocks: &CoverageGraph,
     pass_name: &str,
     body_span: Span,
-    coverage_spans: &Vec<CoverageSpan>,
+    coverage_spans: &[CoverageSpan],
 ) {
     let mir_source = mir_body.source;
     let def_id = mir_source.def_id();
@@ -654,7 +652,7 @@
     tcx: TyCtxt<'tcx>,
     mir_body: &mir::Body<'tcx>,
     basic_coverage_blocks: &CoverageGraph,
-    coverage_spans: &Vec<CoverageSpan>,
+    coverage_spans: &[CoverageSpan],
 ) -> Vec<SpanViewable> {
     let mut span_viewables = Vec::new();
     for coverage_span in coverage_spans {
@@ -676,7 +674,7 @@
     basic_coverage_blocks: &CoverageGraph,
     debug_counters: &DebugCounters,
     graphviz_data: &GraphvizData,
-    intermediate_expressions: &Vec<CoverageKind>,
+    intermediate_expressions: &[CoverageKind],
     debug_used_expressions: &UsedExpressions,
 ) {
     let mir_source = mir_body.source;
@@ -701,7 +699,7 @@
         edge_labels.retain(|label| label != "unreachable");
         let edge_counters = from_terminator
             .successors()
-            .map(|&successor_bb| graphviz_data.get_edge_counter(from_bcb, successor_bb));
+            .map(|successor_bb| graphviz_data.get_edge_counter(from_bcb, successor_bb));
         iter::zip(&edge_labels, edge_counters)
             .map(|(label, some_counter)| {
                 if let Some(counter) = some_counter {
@@ -753,9 +751,9 @@
     mir_body: &mir::Body<'tcx>,
     debug_counters: &DebugCounters,
     bcb_data: &BasicCoverageBlockData,
-    some_coverage_spans_with_counters: Option<&Vec<(CoverageSpan, CoverageKind)>>,
-    some_dependency_counters: Option<&Vec<CoverageKind>>,
-    some_intermediate_expressions: Option<&Vec<CoverageKind>>,
+    some_coverage_spans_with_counters: Option<&[(CoverageSpan, CoverageKind)]>,
+    some_dependency_counters: Option<&[CoverageKind]>,
+    some_intermediate_expressions: Option<&[CoverageKind]>,
 ) -> Vec<String> {
     let len = bcb_data.basic_blocks.len();
     let mut sections = Vec::new();
diff --git a/compiler/rustc_mir_transform/src/coverage/graph.rs b/compiler/rustc_mir_transform/src/coverage/graph.rs
index 6bb7e67..510f1e6 100644
--- a/compiler/rustc_mir_transform/src/coverage/graph.rs
+++ b/compiler/rustc_mir_transform/src/coverage/graph.rs
@@ -481,20 +481,20 @@
 // FIXME(#78544): MIR InstrumentCoverage: Improve coverage of `#[should_panic]` tests and
 // `catch_unwind()` handlers.
 fn bcb_filtered_successors<'a, 'tcx>(
-    body: &'tcx &'a mir::Body<'tcx>,
-    term_kind: &'tcx TerminatorKind<'tcx>,
+    body: &'a mir::Body<'tcx>,
+    term_kind: &'a TerminatorKind<'tcx>,
 ) -> Box<dyn Iterator<Item = BasicBlock> + 'a> {
-    let mut successors = term_kind.successors();
     Box::new(
         match &term_kind {
             // SwitchInt successors are never unwind, and all of them should be traversed.
-            TerminatorKind::SwitchInt { .. } => successors,
+            TerminatorKind::SwitchInt { ref targets, .. } => {
+                None.into_iter().chain(targets.all_targets().into_iter().copied())
+            }
             // For all other kinds, return only the first successor, if any, and ignore unwinds.
             // NOTE: `chain(&[])` is required to coerce the `option::iter` (from
             // `next().into_iter()`) into the `mir::Successors` aliased type.
-            _ => successors.next().into_iter().chain(&[]),
+            _ => term_kind.successors().next().into_iter().chain((&[]).into_iter().copied()),
         }
-        .copied()
         .filter(move |&successor| body[successor].terminator().kind != TerminatorKind::Unreachable),
     )
 }
@@ -691,12 +691,9 @@
 pub struct ShortCircuitPreorder<
     'a,
     'tcx,
-    F: Fn(
-        &'tcx &'a mir::Body<'tcx>,
-        &'tcx TerminatorKind<'tcx>,
-    ) -> Box<dyn Iterator<Item = BasicBlock> + 'a>,
+    F: Fn(&'a mir::Body<'tcx>, &'a TerminatorKind<'tcx>) -> Box<dyn Iterator<Item = BasicBlock> + 'a>,
 > {
-    body: &'tcx &'a mir::Body<'tcx>,
+    body: &'a mir::Body<'tcx>,
     visited: BitSet<BasicBlock>,
     worklist: Vec<BasicBlock>,
     filtered_successors: F,
@@ -705,14 +702,11 @@
 impl<
     'a,
     'tcx,
-    F: Fn(
-        &'tcx &'a mir::Body<'tcx>,
-        &'tcx TerminatorKind<'tcx>,
-    ) -> Box<dyn Iterator<Item = BasicBlock> + 'a>,
+    F: Fn(&'a mir::Body<'tcx>, &'a TerminatorKind<'tcx>) -> Box<dyn Iterator<Item = BasicBlock> + 'a>,
 > ShortCircuitPreorder<'a, 'tcx, F>
 {
     pub fn new(
-        body: &'tcx &'a mir::Body<'tcx>,
+        body: &'a mir::Body<'tcx>,
         filtered_successors: F,
     ) -> ShortCircuitPreorder<'a, 'tcx, F> {
         let worklist = vec![mir::START_BLOCK];
@@ -727,12 +721,9 @@
 }
 
 impl<
-    'a: 'tcx,
+    'a,
     'tcx,
-    F: Fn(
-        &'tcx &'a mir::Body<'tcx>,
-        &'tcx TerminatorKind<'tcx>,
-    ) -> Box<dyn Iterator<Item = BasicBlock> + 'a>,
+    F: Fn(&'a mir::Body<'tcx>, &'a TerminatorKind<'tcx>) -> Box<dyn Iterator<Item = BasicBlock> + 'a>,
 > Iterator for ShortCircuitPreorder<'a, 'tcx, F>
 {
     type Item = (BasicBlock, &'a BasicBlockData<'tcx>);
diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs
index 2bb9f48f..782b620 100644
--- a/compiler/rustc_mir_transform/src/coverage/mod.rs
+++ b/compiler/rustc_mir_transform/src/coverage/mod.rs
@@ -121,7 +121,7 @@
 
         let source_file = source_map.lookup_source_file(body_span.lo());
         let fn_sig_span = match some_fn_sig.filter(|fn_sig| {
-            fn_sig.span.ctxt() == body_span.ctxt()
+            fn_sig.span.eq_ctxt(body_span)
                 && Lrc::ptr_eq(&source_file, &source_map.lookup_source_file(fn_sig.span.lo()))
         }) {
             Some(fn_sig) => fn_sig.span.with_hi(body_span.lo()),
diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs
index 512d4da..82070b9 100644
--- a/compiler/rustc_mir_transform/src/coverage/spans.rs
+++ b/compiler/rustc_mir_transform/src/coverage/spans.rs
@@ -195,7 +195,7 @@
             .expn_span
             .parent_callsite()
             .unwrap_or_else(|| bug!("macro must have a parent"))
-            .ctxt() == body_span.ctxt()
+            .eq_ctxt(body_span)
         {
             return Some(current_macro);
         }
diff --git a/compiler/rustc_mir_transform/src/coverage/tests.rs b/compiler/rustc_mir_transform/src/coverage/tests.rs
index d787443..213bb66 100644
--- a/compiler/rustc_mir_transform/src/coverage/tests.rs
+++ b/compiler/rustc_mir_transform/src/coverage/tests.rs
@@ -37,7 +37,7 @@
 use rustc_index::vec::{Idx, IndexVec};
 use rustc_middle::mir::coverage::CoverageKind;
 use rustc_middle::mir::*;
-use rustc_middle::ty::{self, BOOL_TY};
+use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_span::{self, BytePos, Pos, Span, DUMMY_SP};
 
 // All `TEMP_BLOCK` targets should be replaced before calling `to_body() -> mir::Body`.
@@ -47,6 +47,7 @@
     blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>,
     dummy_place: Place<'tcx>,
     next_local: usize,
+    bool_ty: Ty<'tcx>,
 }
 
 impl<'tcx> MockBlocks<'tcx> {
@@ -55,6 +56,7 @@
             blocks: IndexVec::new(),
             dummy_place: Place { local: RETURN_PLACE, projection: ty::List::empty() },
             next_local: 0,
+            bool_ty: TyCtxt::BOOL_TY_FOR_UNIT_TESTING,
         }
     }
 
@@ -84,7 +86,7 @@
     fn link(&mut self, from_block: BasicBlock, to_block: BasicBlock) {
         match self.blocks[from_block].terminator_mut().kind {
             TerminatorKind::Assert { ref mut target, .. }
-            | TerminatorKind::Call { destination: Some((_, ref mut target)), .. }
+            | TerminatorKind::Call { target: Some(ref mut target), .. }
             | TerminatorKind::Drop { ref mut target, .. }
             | TerminatorKind::DropAndReplace { ref mut target, .. }
             | TerminatorKind::FalseEdge { real_target: ref mut target, .. }
@@ -139,7 +141,8 @@
             TerminatorKind::Call {
                 func: Operand::Copy(self.dummy_place.clone()),
                 args: vec![],
-                destination: Some((self.dummy_place.clone(), TEMP_BLOCK)),
+                destination: self.dummy_place.clone(),
+                target: Some(TEMP_BLOCK),
                 cleanup: None,
                 from_hir_call: false,
                 fn_span: DUMMY_SP,
@@ -154,7 +157,7 @@
     fn switchint(&mut self, some_from_block: Option<BasicBlock>) -> BasicBlock {
         let switchint_kind = TerminatorKind::SwitchInt {
             discr: Operand::Move(Place::from(self.new_temp())),
-            switch_ty: BOOL_TY, // just a dummy value
+            switch_ty: self.bool_ty, // just a dummy value
             targets: SwitchTargets::static_if(0, TEMP_BLOCK, TEMP_BLOCK),
         };
         self.add_block_from(some_from_block, switchint_kind)
@@ -182,7 +185,7 @@
                 let sp = format!("(span:{},{})", span.lo().to_u32(), span.hi().to_u32());
                 match kind {
                     TerminatorKind::Assert { target, .. }
-                    | TerminatorKind::Call { destination: Some((_, target)), .. }
+                    | TerminatorKind::Call { target: Some(target), .. }
                     | TerminatorKind::Drop { target, .. }
                     | TerminatorKind::DropAndReplace { target, .. }
                     | TerminatorKind::FalseEdge { real_target: target, .. }
diff --git a/compiler/rustc_mir_transform/src/dead_store_elimination.rs b/compiler/rustc_mir_transform/src/dead_store_elimination.rs
new file mode 100644
index 0000000..28f3790
--- /dev/null
+++ b/compiler/rustc_mir_transform/src/dead_store_elimination.rs
@@ -0,0 +1,86 @@
+//! This module implements a dead store elimination (DSE) routine.
+//!
+//! This transformation was written specifically for the needs of dest prop. Although it is
+//! perfectly sound to use it in any context that might need it, its behavior should not be changed
+//! without analyzing the interaction this will have with dest prop. Specifically, in addition to
+//! the soundness of this pass in general, dest prop needs it to satisfy two additional conditions:
+//!
+//!  1. It's idempotent, meaning that running this pass a second time immediately after running it a
+//!     first time will not cause any further changes.
+//!  2. This idempotence persists across dest prop's main transform, in other words inserting any
+//!     number of iterations of dest prop between the first and second application of this transform
+//!     will still not cause any further changes.
+//!
+
+use rustc_index::bit_set::BitSet;
+use rustc_middle::mir::*;
+use rustc_middle::ty::TyCtxt;
+use rustc_mir_dataflow::impls::{borrowed_locals, MaybeTransitiveLiveLocals};
+use rustc_mir_dataflow::Analysis;
+
+/// Performs the optimization on the body
+///
+/// The `borrowed` set must be a `BitSet` of all the locals that are ever borrowed in this body. It
+/// can be generated via the [`borrowed_locals`] function.
+pub fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, borrowed: &BitSet<Local>) {
+    let mut live = MaybeTransitiveLiveLocals::new(borrowed)
+        .into_engine(tcx, body)
+        .iterate_to_fixpoint()
+        .into_results_cursor(body);
+
+    let mut patch = Vec::new();
+    for (bb, bb_data) in traversal::preorder(body) {
+        for (statement_index, statement) in bb_data.statements.iter().enumerate().rev() {
+            let loc = Location { block: bb, statement_index };
+            if let StatementKind::Assign(assign) = &statement.kind {
+                if !assign.1.is_safe_to_remove() {
+                    continue;
+                }
+            }
+            match &statement.kind {
+                StatementKind::Assign(box (place, _))
+                | StatementKind::SetDiscriminant { place: box place, .. }
+                | StatementKind::Deinit(box place) => {
+                    if !place.is_indirect() && !borrowed.contains(place.local) {
+                        live.seek_before_primary_effect(loc);
+                        if !live.get().contains(place.local) {
+                            patch.push(loc);
+                        }
+                    }
+                }
+                StatementKind::Retag(_, _)
+                | StatementKind::StorageLive(_)
+                | StatementKind::StorageDead(_)
+                | StatementKind::Coverage(_)
+                | StatementKind::CopyNonOverlapping(_)
+                | StatementKind::Nop => (),
+
+                StatementKind::FakeRead(_) | StatementKind::AscribeUserType(_, _) => {
+                    bug!("{:?} not found in this MIR phase!", &statement.kind)
+                }
+            }
+        }
+    }
+
+    if patch.is_empty() {
+        return;
+    }
+
+    let bbs = body.basic_blocks_mut();
+    for Location { block, statement_index } in patch {
+        bbs[block].statements[statement_index].make_nop();
+    }
+}
+
+pub struct DeadStoreElimination;
+
+impl<'tcx> MirPass<'tcx> for DeadStoreElimination {
+    fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
+        sess.mir_opt_level() >= 2
+    }
+
+    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+        let borrowed = borrowed_locals(body);
+        eliminate(tcx, body, &borrowed);
+    }
+}
diff --git a/compiler/rustc_mir_transform/src/deref_separator.rs b/compiler/rustc_mir_transform/src/deref_separator.rs
index 57a95a6..bfb3ad1 100644
--- a/compiler/rustc_mir_transform/src/deref_separator.rs
+++ b/compiler/rustc_mir_transform/src/deref_separator.rs
@@ -1,9 +1,11 @@
 use crate::MirPass;
 use rustc_index::vec::IndexVec;
 use rustc_middle::mir::patch::MirPatch;
+use rustc_middle::mir::visit::NonUseContext::VarDebugInfo;
 use rustc_middle::mir::visit::{MutVisitor, PlaceContext};
 use rustc_middle::mir::*;
 use rustc_middle::ty::TyCtxt;
+
 pub struct Derefer;
 
 pub struct DerefChecker<'tcx> {
@@ -17,63 +19,68 @@
         self.tcx
     }
 
-    fn visit_place(&mut self, place: &mut Place<'tcx>, _: PlaceContext, loc: Location) {
-        let mut place_local = place.local;
-        let mut last_len = 0;
-        let mut last_deref_idx = 0;
+    fn visit_place(&mut self, place: &mut Place<'tcx>, cntxt: PlaceContext, loc: Location) {
+        if !place.projection.is_empty()
+            && cntxt != PlaceContext::NonUse(VarDebugInfo)
+            && place.projection[1..].contains(&ProjectionElem::Deref)
+        {
+            let mut place_local = place.local;
+            let mut last_len = 0;
+            let mut last_deref_idx = 0;
 
-        let mut prev_temp: Option<Local> = None;
+            let mut prev_temp: Option<Local> = None;
 
-        for (idx, (p_ref, p_elem)) in place.iter_projections().enumerate() {
-            if p_elem == ProjectionElem::Deref && !p_ref.projection.is_empty() {
-                last_deref_idx = idx;
-            }
-        }
-
-        for (idx, (p_ref, p_elem)) in place.iter_projections().enumerate() {
-            if p_elem == ProjectionElem::Deref && !p_ref.projection.is_empty() {
-                let ty = p_ref.ty(&self.local_decls, self.tcx).ty;
-                let temp = self.patcher.new_local_with_info(
-                    ty,
-                    self.local_decls[p_ref.local].source_info.span,
-                    Some(Box::new(LocalInfo::DerefTemp)),
-                );
-
-                self.patcher.add_statement(loc, StatementKind::StorageLive(temp));
-
-                // We are adding current p_ref's projections to our
-                // temp value, excluding projections we already covered.
-                let deref_place = Place::from(place_local)
-                    .project_deeper(&p_ref.projection[last_len..], self.tcx);
-
-                self.patcher.add_assign(
-                    loc,
-                    Place::from(temp),
-                    Rvalue::Use(Operand::Move(deref_place)),
-                );
-                place_local = temp;
-                last_len = p_ref.projection.len();
-
-                // Change `Place` only if we are actually at the Place's last deref
-                if idx == last_deref_idx {
-                    let temp_place =
-                        Place::from(temp).project_deeper(&place.projection[idx..], self.tcx);
-                    *place = temp_place;
+            for (idx, elem) in place.projection[0..].iter().enumerate() {
+                if *elem == ProjectionElem::Deref {
+                    last_deref_idx = idx;
                 }
-
-                // We are destroying the previous temp since it's no longer used.
-                if let Some(prev_temp) = prev_temp {
-                    self.patcher.add_statement(loc, StatementKind::StorageDead(prev_temp));
-                }
-
-                prev_temp = Some(temp);
             }
-        }
+            for (idx, (p_ref, p_elem)) in place.iter_projections().enumerate() {
+                if !p_ref.projection.is_empty() && p_elem == ProjectionElem::Deref {
+                    let ty = p_ref.ty(&self.local_decls, self.tcx).ty;
+                    let temp = self.patcher.new_local_with_info(
+                        ty,
+                        self.local_decls[p_ref.local].source_info.span,
+                        Some(Box::new(LocalInfo::DerefTemp)),
+                    );
 
-        // Since we won't be able to reach final temp, we destroy it outside the loop.
-        if let Some(prev_temp) = prev_temp {
-            let last_loc = Location { block: loc.block, statement_index: loc.statement_index + 1 };
-            self.patcher.add_statement(last_loc, StatementKind::StorageDead(prev_temp));
+                    self.patcher.add_statement(loc, StatementKind::StorageLive(temp));
+
+                    // We are adding current p_ref's projections to our
+                    // temp value, excluding projections we already covered.
+                    let deref_place = Place::from(place_local)
+                        .project_deeper(&p_ref.projection[last_len..], self.tcx);
+
+                    self.patcher.add_assign(
+                        loc,
+                        Place::from(temp),
+                        Rvalue::Use(Operand::Move(deref_place)),
+                    );
+                    place_local = temp;
+                    last_len = p_ref.projection.len();
+
+                    // Change `Place` only if we are actually at the Place's last deref
+                    if idx == last_deref_idx {
+                        let temp_place =
+                            Place::from(temp).project_deeper(&place.projection[idx..], self.tcx);
+                        *place = temp_place;
+                    }
+
+                    // We are destroying the previous temp since it's no longer used.
+                    if let Some(prev_temp) = prev_temp {
+                        self.patcher.add_statement(loc, StatementKind::StorageDead(prev_temp));
+                    }
+
+                    prev_temp = Some(temp);
+                }
+            }
+
+            // Since we won't be able to reach final temp, we destroy it outside the loop.
+            if let Some(prev_temp) = prev_temp {
+                let last_loc =
+                    Location { block: loc.block, statement_index: loc.statement_index + 1 };
+                self.patcher.add_statement(last_loc, StatementKind::StorageDead(prev_temp));
+            }
         }
     }
 }
@@ -92,5 +99,6 @@
 impl<'tcx> MirPass<'tcx> for Derefer {
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         deref_finder(tcx, body);
+        body.phase = MirPhase::Derefered;
     }
 }
diff --git a/compiler/rustc_mir_transform/src/dest_prop.rs b/compiler/rustc_mir_transform/src/dest_prop.rs
index 3732a30..84c7aad 100644
--- a/compiler/rustc_mir_transform/src/dest_prop.rs
+++ b/compiler/rustc_mir_transform/src/dest_prop.rs
@@ -104,7 +104,7 @@
     Rvalue, Statement, StatementKind, Terminator, TerminatorKind,
 };
 use rustc_middle::ty::TyCtxt;
-use rustc_mir_dataflow::impls::{MaybeInitializedLocals, MaybeLiveLocals};
+use rustc_mir_dataflow::impls::{borrowed_locals, MaybeInitializedLocals, MaybeLiveLocals};
 use rustc_mir_dataflow::Analysis;
 
 // Empirical measurements have resulted in some observations:
@@ -575,7 +575,8 @@
             TerminatorKind::Call {
                 func,
                 args,
-                destination: Some((dest_place, _)),
+                destination,
+                target: _,
                 cleanup: _,
                 from_hir_call: _,
                 fn_span: _,
@@ -583,9 +584,9 @@
                 // No arguments may overlap with the destination.
                 for arg in args.iter().chain(Some(func)) {
                     if let Some(place) = arg.place() {
-                        if !place.is_indirect() && !dest_place.is_indirect() {
+                        if !place.is_indirect() && !destination.is_indirect() {
                             self.record_local_conflict(
-                                dest_place.local,
+                                destination.local,
                                 place.local,
                                 "call dest/arg overlap",
                             );
@@ -691,7 +692,6 @@
             }
 
             TerminatorKind::Goto { .. }
-            | TerminatorKind::Call { destination: None, .. }
             | TerminatorKind::SwitchInt { .. }
             | TerminatorKind::Resume
             | TerminatorKind::Abort
@@ -805,7 +805,7 @@
     let mut visitor = FindAssignments {
         body,
         candidates: Vec::new(),
-        ever_borrowed_locals: ever_borrowed_locals(body),
+        ever_borrowed_locals: borrowed_locals(body),
         locals_used_as_array_index: locals_used_as_array_index(body),
     };
     visitor.visit_body(body);
@@ -886,69 +886,6 @@
     }
 }
 
-/// Walks MIR to find all locals that have their address taken anywhere.
-fn ever_borrowed_locals(body: &Body<'_>) -> BitSet<Local> {
-    let mut visitor = BorrowCollector { locals: BitSet::new_empty(body.local_decls.len()) };
-    visitor.visit_body(body);
-    visitor.locals
-}
-
-struct BorrowCollector {
-    locals: BitSet<Local>,
-}
-
-impl<'tcx> Visitor<'tcx> for BorrowCollector {
-    fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
-        self.super_rvalue(rvalue, location);
-
-        match rvalue {
-            Rvalue::AddressOf(_, borrowed_place) | Rvalue::Ref(_, _, borrowed_place) => {
-                if !borrowed_place.is_indirect() {
-                    self.locals.insert(borrowed_place.local);
-                }
-            }
-
-            Rvalue::Cast(..)
-            | Rvalue::ShallowInitBox(..)
-            | Rvalue::Use(..)
-            | Rvalue::Repeat(..)
-            | Rvalue::Len(..)
-            | Rvalue::BinaryOp(..)
-            | Rvalue::CheckedBinaryOp(..)
-            | Rvalue::NullaryOp(..)
-            | Rvalue::UnaryOp(..)
-            | Rvalue::Discriminant(..)
-            | Rvalue::Aggregate(..)
-            | Rvalue::ThreadLocalRef(..) => {}
-        }
-    }
-
-    fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) {
-        self.super_terminator(terminator, location);
-
-        match terminator.kind {
-            TerminatorKind::Drop { place: dropped_place, .. }
-            | TerminatorKind::DropAndReplace { place: dropped_place, .. } => {
-                self.locals.insert(dropped_place.local);
-            }
-
-            TerminatorKind::Abort
-            | TerminatorKind::Assert { .. }
-            | TerminatorKind::Call { .. }
-            | TerminatorKind::FalseEdge { .. }
-            | TerminatorKind::FalseUnwind { .. }
-            | TerminatorKind::GeneratorDrop
-            | TerminatorKind::Goto { .. }
-            | TerminatorKind::Resume
-            | TerminatorKind::Return
-            | TerminatorKind::SwitchInt { .. }
-            | TerminatorKind::Unreachable
-            | TerminatorKind::Yield { .. }
-            | TerminatorKind::InlineAsm { .. } => {}
-        }
-    }
-}
-
 /// `PlaceElem::Index` only stores a `Local`, so we can't replace that with a full `Place`.
 ///
 /// Collect locals used as indices so we don't generate candidates that are impossible to apply
diff --git a/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs b/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs
new file mode 100644
index 0000000..a80d2fb
--- /dev/null
+++ b/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs
@@ -0,0 +1,184 @@
+//! This pass transforms derefs of Box into a deref of the pointer inside Box.
+//!
+//! Box is not actually a pointer so it is incorrect to dereference it directly.
+
+use crate::MirPass;
+use rustc_hir::def_id::DefId;
+use rustc_index::vec::Idx;
+use rustc_middle::mir::patch::MirPatch;
+use rustc_middle::mir::visit::MutVisitor;
+use rustc_middle::mir::*;
+use rustc_middle::ty::subst::Subst;
+use rustc_middle::ty::{Ty, TyCtxt};
+
+/// Constructs the types used when accessing a Box's pointer
+pub fn build_ptr_tys<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    pointee: Ty<'tcx>,
+    unique_did: DefId,
+    nonnull_did: DefId,
+) -> (Ty<'tcx>, Ty<'tcx>, Ty<'tcx>) {
+    let substs = tcx.intern_substs(&[pointee.into()]);
+    let unique_ty = tcx.bound_type_of(unique_did).subst(tcx, substs);
+    let nonnull_ty = tcx.bound_type_of(nonnull_did).subst(tcx, substs);
+    let ptr_ty = tcx.mk_imm_ptr(pointee);
+
+    (unique_ty, nonnull_ty, ptr_ty)
+}
+
+// Constructs the projection needed to access a Box's pointer
+pub fn build_projection<'tcx>(
+    unique_ty: Ty<'tcx>,
+    nonnull_ty: Ty<'tcx>,
+    ptr_ty: Ty<'tcx>,
+) -> [PlaceElem<'tcx>; 3] {
+    [
+        PlaceElem::Field(Field::new(0), unique_ty),
+        PlaceElem::Field(Field::new(0), nonnull_ty),
+        PlaceElem::Field(Field::new(0), ptr_ty),
+    ]
+}
+
+struct ElaborateBoxDerefVisitor<'tcx, 'a> {
+    tcx: TyCtxt<'tcx>,
+    unique_did: DefId,
+    nonnull_did: DefId,
+    local_decls: &'a mut LocalDecls<'tcx>,
+    patch: MirPatch<'tcx>,
+}
+
+impl<'tcx, 'a> MutVisitor<'tcx> for ElaborateBoxDerefVisitor<'tcx, 'a> {
+    fn tcx(&self) -> TyCtxt<'tcx> {
+        self.tcx
+    }
+
+    fn visit_place(
+        &mut self,
+        place: &mut Place<'tcx>,
+        context: visit::PlaceContext,
+        location: Location,
+    ) {
+        let tcx = self.tcx;
+
+        let base_ty = self.local_decls[place.local].ty;
+
+        // Derefer ensures that derefs are always the first projection
+        if place.projection.first() == Some(&PlaceElem::Deref) && base_ty.is_box() {
+            let source_info = self.local_decls[place.local].source_info;
+
+            let (unique_ty, nonnull_ty, ptr_ty) =
+                build_ptr_tys(tcx, base_ty.boxed_ty(), self.unique_did, self.nonnull_did);
+
+            let ptr_local = self.patch.new_temp(ptr_ty, source_info.span);
+            self.local_decls.push(LocalDecl::new(ptr_ty, source_info.span));
+
+            self.patch.add_statement(location, StatementKind::StorageLive(ptr_local));
+
+            self.patch.add_assign(
+                location,
+                Place::from(ptr_local),
+                Rvalue::Use(Operand::Copy(
+                    Place::from(place.local)
+                        .project_deeper(&build_projection(unique_ty, nonnull_ty, ptr_ty), tcx),
+                )),
+            );
+
+            place.local = ptr_local;
+
+            self.patch.add_statement(
+                Location { block: location.block, statement_index: location.statement_index + 1 },
+                StatementKind::StorageDead(ptr_local),
+            );
+        }
+
+        self.super_place(place, context, location);
+    }
+}
+
+pub struct ElaborateBoxDerefs;
+
+impl<'tcx> MirPass<'tcx> for ElaborateBoxDerefs {
+    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+        if let Some(def_id) = tcx.lang_items().owned_box() {
+            let unique_did = tcx.adt_def(def_id).non_enum_variant().fields[0].did;
+
+            let Some(nonnull_def) = tcx.type_of(unique_did).ty_adt_def() else {
+                span_bug!(tcx.def_span(unique_did), "expected Box to contain Unique")
+            };
+
+            let nonnull_did = nonnull_def.non_enum_variant().fields[0].did;
+
+            let patch = MirPatch::new(body);
+
+            let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut();
+
+            let mut visitor =
+                ElaborateBoxDerefVisitor { tcx, unique_did, nonnull_did, local_decls, patch };
+
+            for (block, BasicBlockData { statements, terminator, .. }) in
+                basic_blocks.iter_enumerated_mut()
+            {
+                let mut index = 0;
+                for statement in statements {
+                    let location = Location { block, statement_index: index };
+                    visitor.visit_statement(statement, location);
+                    index += 1;
+                }
+
+                if let Some(terminator) = terminator
+                && !matches!(terminator.kind, TerminatorKind::Yield{..})
+                {
+                    let location = Location { block, statement_index: index };
+                    visitor.visit_terminator(terminator, location);
+                }
+
+                let location = Location { block, statement_index: index };
+                match terminator {
+                    // yielding into a box is handled when lowering generators
+                    Some(Terminator { kind: TerminatorKind::Yield { value, .. }, .. }) => {
+                        visitor.visit_operand(value, location);
+                    }
+                    Some(terminator) => {
+                        visitor.visit_terminator(terminator, location);
+                    }
+                    None => {}
+                }
+            }
+
+            visitor.patch.apply(body);
+
+            for debug_info in body.var_debug_info.iter_mut() {
+                if let VarDebugInfoContents::Place(place) = &mut debug_info.value {
+                    let mut new_projections: Option<Vec<_>> = None;
+                    let mut last_deref = 0;
+
+                    for (i, (base, elem)) in place.iter_projections().enumerate() {
+                        let base_ty = base.ty(&body.local_decls, tcx).ty;
+
+                        if elem == PlaceElem::Deref && base_ty.is_box() {
+                            let new_projections = new_projections.get_or_insert_default();
+
+                            let (unique_ty, nonnull_ty, ptr_ty) =
+                                build_ptr_tys(tcx, base_ty.boxed_ty(), unique_did, nonnull_did);
+
+                            new_projections.extend_from_slice(&base.projection[last_deref..]);
+                            new_projections.extend_from_slice(&build_projection(
+                                unique_ty, nonnull_ty, ptr_ty,
+                            ));
+                            new_projections.push(PlaceElem::Deref);
+
+                            last_deref = i;
+                        }
+                    }
+
+                    if let Some(mut new_projections) = new_projections {
+                        new_projections.extend_from_slice(&place.projection[last_deref..]);
+                        place.projection = tcx.intern_place_elems(&new_projections);
+                    }
+                }
+            }
+        } else {
+            // box is not present, this pass doesn't need to do anything
+        }
+    }
+}
diff --git a/compiler/rustc_mir_transform/src/elaborate_drops.rs b/compiler/rustc_mir_transform/src/elaborate_drops.rs
index f78c7a0..e0e27c5 100644
--- a/compiler/rustc_mir_transform/src/elaborate_drops.rs
+++ b/compiler/rustc_mir_transform/src/elaborate_drops.rs
@@ -470,7 +470,7 @@
         Rvalue::Use(Operand::Constant(Box::new(Constant {
             span,
             user_ty: None,
-            literal: ty::Const::from_bool(self.tcx, val).into(),
+            literal: ConstantKind::from_bool(self.tcx, val),
         })))
     }
 
@@ -494,15 +494,13 @@
     fn drop_flags_for_fn_rets(&mut self) {
         for (bb, data) in self.body.basic_blocks().iter_enumerated() {
             if let TerminatorKind::Call {
-                destination: Some((ref place, tgt)),
-                cleanup: Some(_),
-                ..
+                destination, target: Some(tgt), cleanup: Some(_), ..
             } = data.terminator().kind
             {
                 assert!(!self.patch.is_patched(bb));
 
                 let loc = Location { block: tgt, statement_index: 0 };
-                let path = self.move_data().rev_lookup.find(place.as_ref());
+                let path = self.move_data().rev_lookup.find(destination.as_ref());
                 on_lookup_result_bits(self.tcx, self.body, self.move_data(), path, |child| {
                     self.set_drop_flag(loc, child, DropFlagState::Present)
                 });
@@ -576,14 +574,13 @@
             // There may be a critical edge after this call,
             // so mark the return as initialized *before* the
             // call.
-            if let TerminatorKind::Call {
-                destination: Some((ref place, _)), cleanup: None, ..
-            } = data.terminator().kind
+            if let TerminatorKind::Call { destination, target: Some(_), cleanup: None, .. } =
+                data.terminator().kind
             {
                 assert!(!self.patch.is_patched(bb));
 
                 let loc = Location { block: bb, statement_index: data.statements.len() };
-                let path = self.move_data().rev_lookup.find(place.as_ref());
+                let path = self.move_data().rev_lookup.find(destination.as_ref());
                 on_lookup_result_bits(self.tcx, self.body, self.move_data(), path, |child| {
                     self.set_drop_flag(loc, child, DropFlagState::Present)
                 });
diff --git a/compiler/rustc_mir_transform/src/function_item_references.rs b/compiler/rustc_mir_transform/src/function_item_references.rs
index 1f9bd90..2e4fe1e 100644
--- a/compiler/rustc_mir_transform/src/function_item_references.rs
+++ b/compiler/rustc_mir_transform/src/function_item_references.rs
@@ -37,6 +37,7 @@
             func,
             args,
             destination: _,
+            target: _,
             cleanup: _,
             from_hir_call: _,
             fn_span: _,
diff --git a/compiler/rustc_mir_transform/src/generator.rs b/compiler/rustc_mir_transform/src/generator.rs
index b7dec57..9078b8a 100644
--- a/compiler/rustc_mir_transform/src/generator.rs
+++ b/compiler/rustc_mir_transform/src/generator.rs
@@ -49,13 +49,14 @@
 //! For generators with state 1 (returned) and state 2 (poisoned) it does nothing.
 //! Otherwise it drops all the values in scope at the last suspension point.
 
+use crate::deref_separator::deref_finder;
 use crate::simplify;
 use crate::util::expand_aggregate;
 use crate::MirPass;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir as hir;
 use rustc_hir::lang_items::LangItem;
-use rustc_index::bit_set::{BitMatrix, BitSet};
+use rustc_index::bit_set::{BitMatrix, BitSet, GrowableBitSet};
 use rustc_index::vec::{Idx, IndexVec};
 use rustc_middle::mir::dump_mir;
 use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor};
@@ -194,6 +195,11 @@
 /// Generator has panicked and is poisoned.
 const POISONED: usize = GeneratorSubsts::POISONED;
 
+/// Number of variants to reserve in generator state. Corresponds to
+/// `UNRESUMED` (beginning of a generator) and `RETURNED`/`POISONED`
+/// (end of a generator) states.
+const RESERVED_VARIANTS: usize = 3;
+
 /// A `yield` point in the generator.
 struct SuspensionPoint<'tcx> {
     /// State discriminant used when suspending or resuming at this point.
@@ -205,7 +211,7 @@
     /// Which block to jump to if the generator is dropped in this state.
     drop: Option<BasicBlock>,
     /// Set of locals that have live storage while at this suspension point.
-    storage_liveness: BitSet<Local>,
+    storage_liveness: GrowableBitSet<Local>,
 }
 
 struct TransformVisitor<'tcx> {
@@ -227,7 +233,7 @@
     suspension_points: Vec<SuspensionPoint<'tcx>>,
 
     // The set of locals that have no `StorageLive`/`StorageDead` annotations.
-    always_live_locals: storage::AlwaysLiveLocals,
+    always_live_locals: BitSet<Local>,
 
     // The original RETURN_PLACE local
     new_ret_local: Local,
@@ -344,7 +350,7 @@
             data.statements.extend(self.make_state(state_idx, v, source_info));
             let state = if let Some((resume, mut resume_arg)) = resume {
                 // Yield
-                let state = 3 + self.suspension_points.len();
+                let state = RESERVED_VARIANTS + self.suspension_points.len();
 
                 // The resume arg target location might itself be remapped if its base local is
                 // live across a yield.
@@ -361,7 +367,7 @@
                     resume,
                     resume_arg,
                     drop,
-                    storage_liveness: self.storage_liveness[block].clone().unwrap(),
+                    storage_liveness: self.storage_liveness[block].clone().unwrap().into(),
                 });
 
                 VariantIdx::new(state)
@@ -449,7 +455,7 @@
 fn locals_live_across_suspend_points<'tcx>(
     tcx: TyCtxt<'tcx>,
     body: &Body<'tcx>,
-    always_live_locals: &storage::AlwaysLiveLocals,
+    always_live_locals: &BitSet<Local>,
     movable: bool,
 ) -> LivenessInfo {
     let body_ref: &Body<'_> = &body;
@@ -494,7 +500,8 @@
             let loc = Location { block, statement_index: data.statements.len() };
 
             liveness.seek_to_block_end(block);
-            let mut live_locals = liveness.get().clone();
+            let mut live_locals: BitSet<_> = BitSet::new_empty(body.local_decls.len());
+            live_locals.union(liveness.get());
 
             if !movable {
                 // The `liveness` variable contains the liveness of MIR locals ignoring borrows.
@@ -614,7 +621,7 @@
 fn compute_storage_conflicts<'mir, 'tcx>(
     body: &'mir Body<'tcx>,
     saved_locals: &GeneratorSavedLocals,
-    always_live_locals: storage::AlwaysLiveLocals,
+    always_live_locals: BitSet<Local>,
     requires_storage: rustc_mir_dataflow::Results<'tcx, MaybeRequiresStorage<'mir, 'tcx>>,
 ) -> BitMatrix<GeneratorSavedLocal, GeneratorSavedLocal> {
     assert_eq!(body.local_decls.len(), saved_locals.domain_size());
@@ -624,7 +631,7 @@
 
     // 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();
+    let mut ineligible_locals = always_live_locals;
     ineligible_locals.intersect(&**saved_locals);
 
     // Compute the storage conflicts for all eligible locals.
@@ -790,7 +797,6 @@
     // Leave empty variants for the UNRESUMED, RETURNED, and POISONED states.
     // In debuginfo, these will correspond to the beginning (UNRESUMED) or end
     // (RETURNED, POISONED) of the function.
-    const RESERVED_VARIANTS: usize = 3;
     let body_span = body.source_scopes[OUTERMOST_SOURCE_SCOPE].span;
     let mut variant_source_info: IndexVec<VariantIdx, SourceInfo> = [
         SourceInfo::outermost(body_span.shrink_to_lo()),
@@ -990,7 +996,7 @@
         cond: Operand::Constant(Box::new(Constant {
             span: body.span,
             user_ty: None,
-            literal: ty::Const::from_bool(tcx, false).into(),
+            literal: ConstantKind::from_bool(tcx, false),
         })),
         expected: true,
         msg: message,
@@ -1042,8 +1048,7 @@
             | TerminatorKind::Unreachable
             | TerminatorKind::GeneratorDrop
             | TerminatorKind::FalseEdge { .. }
-            | TerminatorKind::FalseUnwind { .. }
-            | TerminatorKind::InlineAsm { .. } => {}
+            | TerminatorKind::FalseUnwind { .. } => {}
 
             // Resume will *continue* unwinding, but if there's no other unwinding terminator it
             // will never be reached.
@@ -1057,6 +1062,7 @@
             TerminatorKind::Drop { .. }
             | TerminatorKind::DropAndReplace { .. }
             | TerminatorKind::Call { .. }
+            | TerminatorKind::InlineAsm { .. }
             | TerminatorKind::Assert { .. } => return true,
         }
     }
@@ -1176,6 +1182,8 @@
     transform: &TransformVisitor<'tcx>,
     operation: Operation,
 ) -> Vec<(usize, BasicBlock)> {
+    let tcx = transform.tcx;
+
     let source_info = SourceInfo::outermost(body.span);
 
     transform
@@ -1208,13 +1216,85 @@
                 if operation == Operation::Resume {
                     // Move the resume argument to the destination place of the `Yield` terminator
                     let resume_arg = Local::new(2); // 0 = return, 1 = self
-                    statements.push(Statement {
-                        source_info,
-                        kind: StatementKind::Assign(Box::new((
-                            point.resume_arg,
-                            Rvalue::Use(Operand::Move(resume_arg.into())),
-                        ))),
-                    });
+
+                    // handle `box yield` properly
+                    let box_place = if let [projection @ .., ProjectionElem::Deref] =
+                        &**point.resume_arg.projection
+                    {
+                        let box_place =
+                            Place::from(point.resume_arg.local).project_deeper(projection, tcx);
+
+                        let box_ty = box_place.ty(&body.local_decls, tcx).ty;
+
+                        if box_ty.is_box() { Some((box_place, box_ty)) } else { None }
+                    } else {
+                        None
+                    };
+
+                    if let Some((box_place, box_ty)) = box_place {
+                        let unique_did = box_ty
+                            .ty_adt_def()
+                            .expect("expected Box to be an Adt")
+                            .non_enum_variant()
+                            .fields[0]
+                            .did;
+
+                        let Some(nonnull_def) = tcx.type_of(unique_did).ty_adt_def() else {
+                            span_bug!(tcx.def_span(unique_did), "expected Box to contain Unique")
+                        };
+
+                        let nonnull_did = nonnull_def.non_enum_variant().fields[0].did;
+
+                        let (unique_ty, nonnull_ty, ptr_ty) =
+                            crate::elaborate_box_derefs::build_ptr_tys(
+                                tcx,
+                                box_ty.boxed_ty(),
+                                unique_did,
+                                nonnull_did,
+                            );
+
+                        let ptr_local = body.local_decls.push(LocalDecl::new(ptr_ty, body.span));
+
+                        statements.push(Statement {
+                            source_info,
+                            kind: StatementKind::StorageLive(ptr_local),
+                        });
+
+                        statements.push(Statement {
+                            source_info,
+                            kind: StatementKind::Assign(Box::new((
+                                Place::from(ptr_local),
+                                Rvalue::Use(Operand::Copy(box_place.project_deeper(
+                                    &crate::elaborate_box_derefs::build_projection(
+                                        unique_ty, nonnull_ty, ptr_ty,
+                                    ),
+                                    tcx,
+                                ))),
+                            ))),
+                        });
+
+                        statements.push(Statement {
+                            source_info,
+                            kind: StatementKind::Assign(Box::new((
+                                Place::from(ptr_local)
+                                    .project_deeper(&[ProjectionElem::Deref], tcx),
+                                Rvalue::Use(Operand::Move(resume_arg.into())),
+                            ))),
+                        });
+
+                        statements.push(Statement {
+                            source_info,
+                            kind: StatementKind::StorageDead(ptr_local),
+                        });
+                    } else {
+                        statements.push(Statement {
+                            source_info,
+                            kind: StatementKind::Assign(Box::new((
+                                point.resume_arg,
+                                Rvalue::Use(Operand::Move(resume_arg.into())),
+                            ))),
+                        });
+                    }
                 }
 
                 // Then jump to the real target
@@ -1299,7 +1379,7 @@
             },
         );
 
-        let always_live_locals = storage::AlwaysLiveLocals::new(&body);
+        let always_live_locals = storage::always_live_locals(&body);
 
         let liveness_info =
             locals_live_across_suspend_points(tcx, body, &always_live_locals, movable);
@@ -1368,6 +1448,9 @@
 
         // Create the Generator::resume function
         create_generator_resume_function(tcx, transform, body, can_return);
+
+        // Run derefer to fix Derefs that are not in the first place
+        deref_finder(tcx, body);
     }
 }
 
@@ -1459,12 +1542,13 @@
             TerminatorKind::Call {
                 func,
                 args,
-                destination: Some((dest, _)),
+                destination,
+                target: Some(_),
                 cleanup: _,
                 from_hir_call: _,
                 fn_span: _,
             } => {
-                self.check_assigned_place(*dest, |this| {
+                self.check_assigned_place(*destination, |this| {
                     this.visit_operand(func, location);
                     for arg in args {
                         this.visit_operand(arg, location);
diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs
index 012ce73..49403ba 100644
--- a/compiler/rustc_mir_transform/src/inline.rs
+++ b/compiler/rustc_mir_transform/src/inline.rs
@@ -1,5 +1,5 @@
 //! Inlining pass for MIR functions
-
+use crate::deref_separator::deref_finder;
 use rustc_attr::InlineAttr;
 use rustc_index::bit_set::BitSet;
 use rustc_index::vec::Idx;
@@ -17,7 +17,7 @@
 use std::iter;
 use std::ops::{Range, RangeFrom};
 
-crate mod cycle;
+pub(crate) mod cycle;
 
 const INSTR_COST: usize = 5;
 const CALL_PENALTY: usize = 25;
@@ -53,6 +53,7 @@
             debug!("running simplify cfg on {:?}", body.source);
             CfgSimplifier::new(body).simplify();
             remove_dead_blocks(tcx, body);
+            deref_finder(tcx, body);
         }
     }
 }
@@ -157,11 +158,13 @@
             return Err("optimization fuel exhausted");
         }
 
-        let callee_body = callsite.callee.subst_mir_and_normalize_erasing_regions(
+        let Ok(callee_body) = callsite.callee.try_subst_mir_and_normalize_erasing_regions(
             self.tcx,
             self.param_env,
             callee_body.clone(),
-        );
+        ) else {
+            return Err("failed to normalize callee body");
+        };
 
         let old_blocks = caller_body.basic_blocks().next_index();
         self.inline_call(caller_body, &callsite, callee_body);
@@ -248,11 +251,11 @@
     ) -> Option<CallSite<'tcx>> {
         // Only consider direct calls to functions
         let terminator = bb_data.terminator();
-        if let TerminatorKind::Call { ref func, ref destination, .. } = terminator.kind {
+        if let TerminatorKind::Call { ref func, target, .. } = terminator.kind {
             let func_ty = func.ty(caller_body, self.tcx);
             if let ty::FnDef(def_id, substs) = *func_ty.kind() {
                 // To resolve an instance its substs have to be fully normalized.
-                let substs = self.tcx.normalize_erasing_regions(self.param_env, substs);
+                let substs = self.tcx.try_normalize_erasing_regions(self.param_env, substs).ok()?;
                 let callee =
                     Instance::resolve(self.tcx, self.param_env, def_id, substs).ok().flatten()?;
 
@@ -266,7 +269,7 @@
                     callee,
                     fn_sig,
                     block: bb,
-                    target: destination.map(|(_, target)| target),
+                    target,
                     source_info: terminator.source_info,
                 });
             }
@@ -395,7 +398,7 @@
                     }
                 }
 
-                TerminatorKind::Unreachable | TerminatorKind::Call { destination: None, .. }
+                TerminatorKind::Unreachable | TerminatorKind::Call { target: None, .. }
                     if first_block =>
                 {
                     // If the function always diverges, don't inline
@@ -407,19 +410,21 @@
                     if let ty::FnDef(def_id, substs) =
                         *callsite.callee.subst_mir(self.tcx, &f.literal.ty()).kind()
                     {
-                        let substs = self.tcx.normalize_erasing_regions(self.param_env, substs);
-                        if let Ok(Some(instance)) =
-                            Instance::resolve(self.tcx, self.param_env, def_id, substs)
+                        if let Ok(substs) =
+                            self.tcx.try_normalize_erasing_regions(self.param_env, substs)
                         {
-                            if callsite.callee.def_id() == instance.def_id() {
-                                return Err("self-recursion");
-                            } else if self.history.contains(&instance) {
-                                return Err("already inlined");
+                            if let Ok(Some(instance)) =
+                                Instance::resolve(self.tcx, self.param_env, def_id, substs)
+                            {
+                                if callsite.callee.def_id() == instance.def_id() {
+                                    return Err("self-recursion");
+                                } else if self.history.contains(&instance) {
+                                    return Err("already inlined");
+                                }
                             }
                         }
                         // Don't give intrinsics the extra penalty for calls
-                        let f = tcx.fn_sig(def_id);
-                        if f.abi() == Abi::RustIntrinsic || f.abi() == Abi::PlatformIntrinsic {
+                        if tcx.is_intrinsic(def_id) {
                             cost += INSTR_COST;
                         } else {
                             cost += CALL_PENALTY;
@@ -450,7 +455,7 @@
             }
 
             if !is_drop {
-                for &succ in term.successors() {
+                for succ in term.successors() {
                     work_list.push(succ);
                 }
             }
@@ -513,27 +518,22 @@
                     false
                 }
 
-                let dest = if let Some((destination_place, _)) = destination {
-                    if dest_needs_borrow(destination_place) {
-                        trace!("creating temp for return destination");
-                        let dest = Rvalue::Ref(
-                            self.tcx.lifetimes.re_erased,
-                            BorrowKind::Mut { allow_two_phase_borrow: false },
-                            destination_place,
-                        );
-                        let dest_ty = dest.ty(caller_body, self.tcx);
-                        let temp = Place::from(self.new_call_temp(caller_body, &callsite, dest_ty));
-                        caller_body[callsite.block].statements.push(Statement {
-                            source_info: callsite.source_info,
-                            kind: StatementKind::Assign(Box::new((temp, dest))),
-                        });
-                        self.tcx.mk_place_deref(temp)
-                    } else {
-                        destination_place
-                    }
+                let dest = if dest_needs_borrow(destination) {
+                    trace!("creating temp for return destination");
+                    let dest = Rvalue::Ref(
+                        self.tcx.lifetimes.re_erased,
+                        BorrowKind::Mut { allow_two_phase_borrow: false },
+                        destination,
+                    );
+                    let dest_ty = dest.ty(caller_body, self.tcx);
+                    let temp = Place::from(self.new_call_temp(caller_body, &callsite, dest_ty));
+                    caller_body[callsite.block].statements.push(Statement {
+                        source_info: callsite.source_info,
+                        kind: StatementKind::Assign(Box::new((temp, dest))),
+                    });
+                    self.tcx.mk_place_deref(temp)
                 } else {
-                    trace!("creating temp for return place");
-                    Place::from(self.new_call_temp(caller_body, &callsite, callee_body.return_ty()))
+                    destination
                 };
 
                 // Copy the arguments if needed.
@@ -555,7 +555,8 @@
                     new_scopes: SourceScope::new(caller_body.source_scopes.len())..,
                     new_blocks: BasicBlock::new(caller_body.basic_blocks().len())..,
                     destination: dest,
-                    return_block: callsite.target,
+                    callsite_scope: caller_body.source_scopes[callsite.source_info.scope].clone(),
+                    callsite,
                     cleanup_block: cleanup,
                     in_cleanup_block: false,
                     tcx: self.tcx,
@@ -567,31 +568,6 @@
                 // (or existing ones, in a few special cases) in the caller.
                 integrator.visit_body(&mut callee_body);
 
-                for scope in &mut callee_body.source_scopes {
-                    // FIXME(eddyb) move this into a `fn visit_scope_data` in `Integrator`.
-                    if scope.parent_scope.is_none() {
-                        let callsite_scope = &caller_body.source_scopes[callsite.source_info.scope];
-
-                        // Attach the outermost callee scope as a child of the callsite
-                        // scope, via the `parent_scope` and `inlined_parent_scope` chains.
-                        scope.parent_scope = Some(callsite.source_info.scope);
-                        assert_eq!(scope.inlined_parent_scope, None);
-                        scope.inlined_parent_scope = if callsite_scope.inlined.is_some() {
-                            Some(callsite.source_info.scope)
-                        } else {
-                            callsite_scope.inlined_parent_scope
-                        };
-
-                        // Mark the outermost callee scope as an inlined one.
-                        assert_eq!(scope.inlined, None);
-                        scope.inlined = Some((callsite.callee, callsite.source_info.span));
-                    } else if scope.inlined_parent_scope.is_none() {
-                        // Make it easy to find the scope with `inlined` set above.
-                        scope.inlined_parent_scope =
-                            Some(integrator.map_scope(OUTERMOST_SOURCE_SCOPE));
-                    }
-                }
-
                 // If there are any locals without storage markers, give them storage only for the
                 // duration of the call.
                 for local in callee_body.vars_and_temps_iter() {
@@ -638,7 +614,7 @@
                 caller_body.required_consts.extend(
                     callee_body.required_consts.iter().copied().filter(|&ct| {
                         match ct.literal.const_for_ty() {
-                            Some(ct) => matches!(ct.val(), ConstKind::Unevaluated(_)),
+                            Some(ct) => matches!(ct.kind(), ConstKind::Unevaluated(_)),
                             None => true,
                         }
                     }),
@@ -787,7 +763,8 @@
     new_scopes: RangeFrom<SourceScope>,
     new_blocks: RangeFrom<BasicBlock>,
     destination: Place<'tcx>,
-    return_block: Option<BasicBlock>,
+    callsite_scope: SourceScopeData<'tcx>,
+    callsite: &'a CallSite<'tcx>,
     cleanup_block: Option<BasicBlock>,
     in_cleanup_block: bool,
     tcx: TyCtxt<'tcx>,
@@ -833,6 +810,28 @@
         *local = self.map_local(*local);
     }
 
+    fn visit_source_scope_data(&mut self, scope_data: &mut SourceScopeData<'tcx>) {
+        self.super_source_scope_data(scope_data);
+        if scope_data.parent_scope.is_none() {
+            // Attach the outermost callee scope as a child of the callsite
+            // scope, via the `parent_scope` and `inlined_parent_scope` chains.
+            scope_data.parent_scope = Some(self.callsite.source_info.scope);
+            assert_eq!(scope_data.inlined_parent_scope, None);
+            scope_data.inlined_parent_scope = if self.callsite_scope.inlined.is_some() {
+                Some(self.callsite.source_info.scope)
+            } else {
+                self.callsite_scope.inlined_parent_scope
+            };
+
+            // Mark the outermost callee scope as an inlined one.
+            assert_eq!(scope_data.inlined, None);
+            scope_data.inlined = Some((self.callsite.callee, self.callsite.source_info.span));
+        } else if scope_data.inlined_parent_scope.is_none() {
+            // Make it easy to find the scope with `inlined` set above.
+            scope_data.inlined_parent_scope = Some(self.map_scope(OUTERMOST_SOURCE_SCOPE));
+        }
+    }
+
     fn visit_source_scope(&mut self, scope: &mut SourceScope) {
         *scope = self.map_scope(*scope);
     }
@@ -916,8 +915,8 @@
                     *unwind = self.cleanup_block;
                 }
             }
-            TerminatorKind::Call { ref mut destination, ref mut cleanup, .. } => {
-                if let Some((_, ref mut tgt)) = *destination {
+            TerminatorKind::Call { ref mut target, ref mut cleanup, .. } => {
+                if let Some(ref mut tgt) = *target {
                     *tgt = self.map_block(*tgt);
                 }
                 if let Some(tgt) = *cleanup {
@@ -939,7 +938,7 @@
                 }
             }
             TerminatorKind::Return => {
-                terminator.kind = if let Some(tgt) = self.return_block {
+                terminator.kind = if let Some(tgt) = self.callsite.target {
                     TerminatorKind::Goto { target: tgt }
                 } else {
                     TerminatorKind::Unreachable
diff --git a/compiler/rustc_mir_transform/src/inline/cycle.rs b/compiler/rustc_mir_transform/src/inline/cycle.rs
index bee6aee..fd7de2b 100644
--- a/compiler/rustc_mir_transform/src/inline/cycle.rs
+++ b/compiler/rustc_mir_transform/src/inline/cycle.rs
@@ -9,7 +9,7 @@
 // FIXME: check whether it is cheaper to precompute the entire call graph instead of invoking
 // this query ridiculously often.
 #[instrument(level = "debug", skip(tcx, root, target))]
-crate fn mir_callgraph_reachable<'tcx>(
+pub(crate) fn mir_callgraph_reachable<'tcx>(
     tcx: TyCtxt<'tcx>,
     (root, target): (ty::Instance<'tcx>, LocalDefId),
 ) -> bool {
@@ -136,7 +136,7 @@
     )
 }
 
-crate fn mir_inliner_callees<'tcx>(
+pub(crate) fn mir_inliner_callees<'tcx>(
     tcx: TyCtxt<'tcx>,
     instance: ty::InstanceDef<'tcx>,
 ) -> &'tcx [(DefId, SubstsRef<'tcx>)] {
diff --git a/compiler/rustc_mir_transform/src/instcombine.rs b/compiler/rustc_mir_transform/src/instcombine.rs
index d1c4a4b..ea10ec5 100644
--- a/compiler/rustc_mir_transform/src/instcombine.rs
+++ b/compiler/rustc_mir_transform/src/instcombine.rs
@@ -3,8 +3,8 @@
 use crate::MirPass;
 use rustc_hir::Mutability;
 use rustc_middle::mir::{
-    BinOp, Body, Constant, LocalDecls, Operand, Place, ProjectionElem, Rvalue, SourceInfo,
-    Statement, StatementKind, Terminator, TerminatorKind, UnOp,
+    BinOp, Body, Constant, ConstantKind, LocalDecls, Operand, Place, ProjectionElem, Rvalue,
+    SourceInfo, Statement, StatementKind, Terminator, TerminatorKind, UnOp,
 };
 use rustc_middle::ty::{self, TyCtxt};
 
@@ -129,8 +129,8 @@
                     return;
                 }
 
-                let constant =
-                    Constant { span: source_info.span, literal: len.into(), user_ty: None };
+                let literal = ConstantKind::from_const(len, self.tcx);
+                let constant = Constant { span: source_info.span, literal, user_ty: None };
                 *rvalue = Rvalue::Use(Operand::Constant(Box::new(constant)));
             }
         }
@@ -141,7 +141,7 @@
         terminator: &mut Terminator<'tcx>,
         statements: &mut Vec<Statement<'tcx>>,
     ) {
-        let TerminatorKind::Call { func, args, destination, .. } = &mut terminator.kind
+        let TerminatorKind::Call { func, args, destination, target, .. } = &mut terminator.kind
         else { return };
 
         // It's definitely not a clone if there are multiple arguments
@@ -149,7 +149,7 @@
             return;
         }
 
-        let Some((destination_place, destination_block)) = *destination
+        let Some(destination_block) = *target
         else { return };
 
         // Only bother looking more if it's easy to know what we're calling
@@ -192,12 +192,12 @@
 
         statements.push(Statement {
             source_info: terminator.source_info,
-            kind: StatementKind::Assign(box (
-                destination_place,
+            kind: StatementKind::Assign(Box::new((
+                *destination,
                 Rvalue::Use(Operand::Copy(
                     arg_place.project_deeper(&[ProjectionElem::Deref], self.tcx),
                 )),
-            )),
+            ))),
         });
         terminator.kind = TerminatorKind::Goto { target: destination_block };
     }
diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs
index 40cc6da..b7caa61 100644
--- a/compiler/rustc_mir_transform/src/lib.rs
+++ b/compiler/rustc_mir_transform/src/lib.rs
@@ -1,7 +1,5 @@
 #![allow(rustc::potential_query_instability)]
 #![feature(box_patterns)]
-#![feature(box_syntax)]
-#![feature(crate_visibility_modifier)]
 #![feature(let_chains)]
 #![feature(let_else)]
 #![feature(map_try_insert)]
@@ -11,6 +9,7 @@
 #![feature(option_get_or_insert_default)]
 #![feature(trusted_step)]
 #![feature(try_blocks)]
+#![feature(yeet_expr)]
 #![recursion_limit = "256"]
 
 #[macro_use]
@@ -51,12 +50,14 @@
 mod const_prop;
 mod const_prop_lint;
 mod coverage;
+mod dead_store_elimination;
 mod deaggregator;
 mod deduplicate_blocks;
 mod deref_separator;
 mod dest_prop;
 pub mod dump_mir;
 mod early_otherwise_branch;
+mod elaborate_box_derefs;
 mod elaborate_drops;
 mod function_item_references;
 mod generator;
@@ -170,7 +171,7 @@
             intravisit::walk_struct_def(self, v)
         }
     }
-    tcx.hir().visit_all_item_likes(&mut GatherCtors { tcx, set: &mut set }.as_deep_visitor());
+    tcx.hir().deep_visit_all_item_likes(&mut GatherCtors { tcx, set: &mut set });
 
     set
 }
@@ -427,6 +428,7 @@
         // `AddRetag` needs to run after `ElaborateDrops`. Otherwise it should run fairly late,
         // but before optimizations begin.
         &deref_separator::Derefer,
+        &elaborate_box_derefs::ElaborateBoxDerefs,
         &add_retag::AddRetag,
         &lower_intrinsics::LowerIntrinsics,
         &simplify::SimplifyCfg::new("elaborate-drops"),
@@ -483,17 +485,18 @@
             &const_prop::ConstProp,
             //
             // Const-prop runs unconditionally, but doesn't mutate the MIR at mir-opt-level=0.
+            &const_debuginfo::ConstDebugInfo,
             &o1(simplify_branches::SimplifyConstCondition::new("after-const-prop")),
             &early_otherwise_branch::EarlyOtherwiseBranch,
             &simplify_comparison_integral::SimplifyComparisonIntegral,
             &simplify_try::SimplifyArmIdentity,
             &simplify_try::SimplifyBranchSame,
+            &dead_store_elimination::DeadStoreElimination,
             &dest_prop::DestinationPropagation,
             &o1(simplify_branches::SimplifyConstCondition::new("final")),
             &o1(remove_noop_landing_pads::RemoveNoopLandingPads),
             &o1(simplify::SimplifyCfg::new("final")),
             &nrvo::RenameReturnPlace,
-            &const_debuginfo::ConstDebugInfo,
             &simplify::SimplifyLocals,
             &multiple_return_terminators::MultipleReturnTerminators,
             &deduplicate_blocks::DeduplicateBlocks,
@@ -530,8 +533,10 @@
         None => {}
         Some(other) => panic!("do not use `optimized_mir` for constants: {:?}", other),
     }
+    debug!("about to call mir_drops_elaborated...");
     let mut body =
         tcx.mir_drops_elaborated_and_const_checked(ty::WithOptConstParam::unknown(did)).steal();
+    debug!("body: {:#?}", body);
     run_optimization_passes(tcx, &mut body);
 
     debug_assert!(!body.has_free_regions(), "Free regions in optimized MIR");
diff --git a/compiler/rustc_mir_transform/src/lower_intrinsics.rs b/compiler/rustc_mir_transform/src/lower_intrinsics.rs
index 684d988..989b94b 100644
--- a/compiler/rustc_mir_transform/src/lower_intrinsics.rs
+++ b/compiler/rustc_mir_transform/src/lower_intrinsics.rs
@@ -6,7 +6,6 @@
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_span::symbol::{sym, Symbol};
 use rustc_span::Span;
-use rustc_target::spec::abi::Abi;
 
 pub struct LowerIntrinsics;
 
@@ -15,7 +14,9 @@
         let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut();
         for block in basic_blocks {
             let terminator = block.terminator.as_mut().unwrap();
-            if let TerminatorKind::Call { func, args, destination, .. } = &mut terminator.kind {
+            if let TerminatorKind::Call { func, args, destination, target, .. } =
+                &mut terminator.kind
+            {
                 let func_ty = func.ty(local_decls, tcx);
                 let Some((intrinsic_name, substs)) = resolve_rust_intrinsic(tcx, func_ty) else {
                     continue;
@@ -25,15 +26,15 @@
                         terminator.kind = TerminatorKind::Unreachable;
                     }
                     sym::forget => {
-                        if let Some((destination, target)) = *destination {
+                        if let Some(target) = *target {
                             block.statements.push(Statement {
                                 source_info: terminator.source_info,
                                 kind: StatementKind::Assign(Box::new((
-                                    destination,
+                                    *destination,
                                     Rvalue::Use(Operand::Constant(Box::new(Constant {
                                         span: terminator.source_info.span,
                                         user_ty: None,
-                                        literal: ty::Const::zero_sized(tcx, tcx.types.unit).into(),
+                                        literal: ConstantKind::zero_sized(tcx.types.unit),
                                     }))),
                                 ))),
                             });
@@ -41,7 +42,7 @@
                         }
                     }
                     sym::copy_nonoverlapping => {
-                        let target = destination.unwrap().1;
+                        let target = target.unwrap();
                         let mut args = args.drain(..);
                         block.statements.push(Statement {
                             source_info: terminator.source_info,
@@ -62,7 +63,7 @@
                         terminator.kind = TerminatorKind::Goto { target };
                     }
                     sym::wrapping_add | sym::wrapping_sub | sym::wrapping_mul => {
-                        if let Some((destination, target)) = *destination {
+                        if let Some(target) = *target {
                             let lhs;
                             let rhs;
                             {
@@ -79,7 +80,7 @@
                             block.statements.push(Statement {
                                 source_info: terminator.source_info,
                                 kind: StatementKind::Assign(Box::new((
-                                    destination,
+                                    *destination,
                                     Rvalue::BinaryOp(bin_op, Box::new((lhs, rhs))),
                                 ))),
                             });
@@ -92,7 +93,7 @@
                         // during codegen. Issue #35310.
                     }
                     sym::size_of | sym::min_align_of => {
-                        if let Some((destination, target)) = *destination {
+                        if let Some(target) = *target {
                             let tp_ty = substs.type_at(0);
                             let null_op = match intrinsic_name {
                                 sym::size_of => NullOp::SizeOf,
@@ -102,7 +103,7 @@
                             block.statements.push(Statement {
                                 source_info: terminator.source_info,
                                 kind: StatementKind::Assign(Box::new((
-                                    destination,
+                                    *destination,
                                     Rvalue::NullaryOp(null_op, tp_ty),
                                 ))),
                             });
@@ -110,14 +111,12 @@
                         }
                     }
                     sym::discriminant_value => {
-                        if let (Some((destination, target)), Some(arg)) =
-                            (*destination, args[0].place())
-                        {
+                        if let (Some(target), Some(arg)) = (*target, args[0].place()) {
                             let arg = tcx.mk_place_deref(arg);
                             block.statements.push(Statement {
                                 source_info: terminator.source_info,
                                 kind: StatementKind::Assign(Box::new((
-                                    destination,
+                                    *destination,
                                     Rvalue::Discriminant(arg),
                                 ))),
                             });
@@ -139,8 +138,7 @@
     func_ty: Ty<'tcx>,
 ) -> Option<(Symbol, SubstsRef<'tcx>)> {
     if let ty::FnDef(def_id, substs) = *func_ty.kind() {
-        let fn_sig = func_ty.fn_sig(tcx);
-        if let Abi::RustIntrinsic | Abi::PlatformIntrinsic = fn_sig.abi() {
+        if tcx.is_intrinsic(def_id) {
             return Some((tcx.item_name(def_id), substs));
         }
     }
diff --git a/compiler/rustc_mir_transform/src/lower_slice_len.rs b/compiler/rustc_mir_transform/src/lower_slice_len.rs
index 43d1d62..07163cf 100644
--- a/compiler/rustc_mir_transform/src/lower_slice_len.rs
+++ b/compiler/rustc_mir_transform/src/lower_slice_len.rs
@@ -52,7 +52,8 @@
         TerminatorKind::Call {
             func,
             args,
-            destination: Some((dest, bb)),
+            destination,
+            target: Some(bb),
             cleanup: None,
             from_hir_call: true,
             ..
@@ -73,7 +74,8 @@
                     // make new RValue for Len
                     let deref_arg = tcx.mk_place_deref(arg);
                     let r_value = Rvalue::Len(deref_arg);
-                    let len_statement_kind = StatementKind::Assign(Box::new((*dest, r_value)));
+                    let len_statement_kind =
+                        StatementKind::Assign(Box::new((*destination, r_value)));
                     let add_statement =
                         Statement { kind: len_statement_kind, source_info: terminator.source_info };
 
diff --git a/compiler/rustc_mir_transform/src/normalize_array_len.rs b/compiler/rustc_mir_transform/src/normalize_array_len.rs
index cdfd49e..0f45711 100644
--- a/compiler/rustc_mir_transform/src/normalize_array_len.rs
+++ b/compiler/rustc_mir_transform/src/normalize_array_len.rs
@@ -125,7 +125,7 @@
                             let assign_to = Place::from(local);
                             let rvalue = Rvalue::Use(operand);
                             make_copy_statement.kind =
-                                StatementKind::Assign(box (assign_to, rvalue));
+                                StatementKind::Assign(Box::new((assign_to, rvalue)));
                             statements.push(make_copy_statement);
 
                             // to reorder we have to copy and make NOP
@@ -165,7 +165,8 @@
                     if add_deref {
                         place = self.tcx.mk_place_deref(place);
                     }
-                    len_statement.kind = StatementKind::Assign(box (*into, Rvalue::Len(place)));
+                    len_statement.kind =
+                        StatementKind::Assign(Box::new((*into, Rvalue::Len(place))));
                     statements.push(len_statement);
 
                     // make temporary dead
diff --git a/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs b/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs
index 4d214b0..89808d3d 100644
--- a/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs
+++ b/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs
@@ -15,7 +15,7 @@
         sess.panic_strategy() != PanicStrategy::Abort
     }
 
-    fn run_pass(&self, _: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+    fn run_pass(&self, _tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         debug!("remove_noop_landing_pads({:?})", body);
         self.remove_nop_landing_pads(body)
     }
@@ -65,7 +65,7 @@
             | TerminatorKind::SwitchInt { .. }
             | TerminatorKind::FalseEdge { .. }
             | TerminatorKind::FalseUnwind { .. } => {
-                terminator.successors().all(|&succ| nop_landing_pads.contains(succ))
+                terminator.successors().all(|succ| nop_landing_pads.contains(succ))
             }
             TerminatorKind::GeneratorDrop
             | TerminatorKind::Yield { .. }
@@ -81,6 +81,8 @@
     }
 
     fn remove_nop_landing_pads(&self, body: &mut Body<'_>) {
+        debug!("body: {:#?}", body);
+
         // make sure there's a single resume block
         let resume_block = {
             let patch = MirPatch::new(body);
diff --git a/compiler/rustc_mir_transform/src/required_consts.rs b/compiler/rustc_mir_transform/src/required_consts.rs
index b87220a..827ce0c 100644
--- a/compiler/rustc_mir_transform/src/required_consts.rs
+++ b/compiler/rustc_mir_transform/src/required_consts.rs
@@ -15,7 +15,7 @@
 impl<'tcx> Visitor<'tcx> for RequiredConstsVisitor<'_, 'tcx> {
     fn visit_constant(&mut self, constant: &Constant<'tcx>, _: Location) {
         let literal = constant.literal;
-        if let Some(ct) = literal.const_for_ty() && let ConstKind::Unevaluated(_) = ct.val() {
+        if let Some(ct) = literal.const_for_ty() && let ConstKind::Unevaluated(_) = ct.kind() {
             self.required_consts.push(*constant);
         }
     }
diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs
index 016b3bc..3be1783 100644
--- a/compiler/rustc_mir_transform/src/shim.rs
+++ b/compiler/rustc_mir_transform/src/shim.rs
@@ -430,7 +430,7 @@
         let func = Operand::Constant(Box::new(Constant {
             span: self.span,
             user_ty: None,
-            literal: ty::Const::zero_sized(tcx, func_ty).into(),
+            literal: ConstantKind::zero_sized(func_ty),
         }));
 
         let ref_loc = self.make_place(
@@ -450,7 +450,8 @@
             TerminatorKind::Call {
                 func,
                 args: vec![Operand::Move(ref_loc)],
-                destination: Some((dest, next)),
+                destination: dest,
+                target: Some(next),
                 cleanup: Some(cleanup),
                 from_hir_call: true,
                 fn_span: self.span,
@@ -629,7 +630,7 @@
                 Operand::Constant(Box::new(Constant {
                     span,
                     user_ty: None,
-                    literal: ty::Const::zero_sized(tcx, ty).into(),
+                    literal: ConstantKind::zero_sized(ty),
                 })),
                 rcvr.into_iter().collect::<Vec<_>>(),
             )
@@ -676,7 +677,8 @@
         TerminatorKind::Call {
             func: callee,
             args,
-            destination: Some((Place::return_place(), BasicBlock::new(1))),
+            destination: Place::return_place(),
+            target: Some(BasicBlock::new(1)),
             cleanup: if let Some(Adjustment::RefMut) = rcvr_adjustment {
                 Some(BasicBlock::new(3))
             } else {
diff --git a/compiler/rustc_mir_transform/src/simplify.rs b/compiler/rustc_mir_transform/src/simplify.rs
index b42e390..8a78ea5 100644
--- a/compiler/rustc_mir_transform/src/simplify.rs
+++ b/compiler/rustc_mir_transform/src/simplify.rs
@@ -81,7 +81,7 @@
 
         for (_, data) in traversal::preorder(body) {
             if let Some(ref term) = data.terminator {
-                for &tgt in term.successors() {
+                for tgt in term.successors() {
                     pred_count[tgt] += 1;
                 }
             }
@@ -235,8 +235,8 @@
         };
 
         let first_succ = {
-            if let Some(&first_succ) = terminator.successors().next() {
-                if terminator.successors().all(|s| *s == first_succ) {
+            if let Some(first_succ) = terminator.successors().next() {
+                if terminator.successors().all(|s| s == first_succ) {
                     let count = terminator.successors().count();
                     self.pred_count[first_succ] -= (count - 1) as u32;
                     first_succ
@@ -494,8 +494,12 @@
             StatementKind::StorageLive(_local) | StatementKind::StorageDead(_local) => {}
 
             StatementKind::Assign(box (ref place, ref rvalue)) => {
-                self.visit_lhs(place, location);
-                self.visit_rvalue(rvalue, location);
+                if rvalue.is_safe_to_remove() {
+                    self.visit_lhs(place, location);
+                    self.visit_rvalue(rvalue, location);
+                } else {
+                    self.super_statement(statement, location);
+                }
             }
 
             StatementKind::SetDiscriminant { ref place, variant_index: _ }
diff --git a/compiler/rustc_monomorphize/Cargo.toml b/compiler/rustc_monomorphize/Cargo.toml
index f812afe..e4ac47f 100644
--- a/compiler/rustc_monomorphize/Cargo.toml
+++ b/compiler/rustc_monomorphize/Cargo.toml
@@ -10,7 +10,6 @@
 smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
 tracing = "0.1"
 rustc_data_structures = { path = "../rustc_data_structures" }
-rustc_errors = { path = "../rustc_errors" }
 rustc_hir = { path = "../rustc_hir" }
 rustc_index = { path = "../rustc_index" }
 rustc_middle = { path = "../rustc_middle" }
diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs
index ee02151..2af22e1 100644
--- a/compiler/rustc_monomorphize/src/collector.rs
+++ b/compiler/rustc_monomorphize/src/collector.rs
@@ -201,7 +201,6 @@
 use rustc_session::Limit;
 use rustc_span::source_map::{dummy_spanned, respan, Span, Spanned, DUMMY_SP};
 use rustc_target::abi::Size;
-use smallvec::SmallVec;
 use std::iter;
 use std::ops::Range;
 use std::path::PathBuf;
@@ -226,6 +225,44 @@
     inlines: GrowableBitSet<usize>,
 }
 
+/// Struct to store mono items in each collecting and if they should
+/// be inlined. We call `instantiation_mode` to get their inlining
+/// status when inserting new elements, which avoids calling it in
+/// `inlining_map.lock_mut()`. See the `collect_items_rec` implementation
+/// below.
+struct MonoItems<'tcx> {
+    // If this is false, we do not need to compute whether items
+    // will need to be inlined.
+    compute_inlining: bool,
+
+    // The TyCtxt used to determine whether the a item should
+    // be inlined.
+    tcx: TyCtxt<'tcx>,
+
+    // The collected mono items. The bool field in each element
+    // indicates whether this element should be inlined.
+    items: Vec<(Spanned<MonoItem<'tcx>>, bool /*inlined*/)>,
+}
+
+impl<'tcx> MonoItems<'tcx> {
+    #[inline]
+    fn push(&mut self, item: Spanned<MonoItem<'tcx>>) {
+        self.extend([item]);
+    }
+
+    #[inline]
+    fn extend<T: IntoIterator<Item = Spanned<MonoItem<'tcx>>>>(&mut self, iter: T) {
+        self.items.extend(iter.into_iter().map(|mono_item| {
+            let inlined = if !self.compute_inlining {
+                false
+            } else {
+                mono_item.node.instantiation_mode(self.tcx) == InstantiationMode::LocalCopy
+            };
+            (mono_item, inlined)
+        }))
+    }
+}
+
 impl<'tcx> InliningMap<'tcx> {
     fn new() -> InliningMap<'tcx> {
         InliningMap {
@@ -235,7 +272,13 @@
         }
     }
 
-    fn record_accesses(&mut self, source: MonoItem<'tcx>, new_targets: &[(MonoItem<'tcx>, bool)]) {
+    fn record_accesses<'a>(
+        &mut self,
+        source: MonoItem<'tcx>,
+        new_targets: &'a [(Spanned<MonoItem<'tcx>>, bool)],
+    ) where
+        'tcx: 'a,
+    {
         let start_index = self.targets.len();
         let new_items_count = new_targets.len();
         let new_items_count_total = new_items_count + self.targets.len();
@@ -243,9 +286,9 @@
         self.targets.reserve(new_items_count);
         self.inlines.ensure(new_items_count_total);
 
-        for (i, (target, inline)) in new_targets.iter().enumerate() {
-            self.targets.push(*target);
-            if *inline {
+        for (i, (Spanned { node: mono_item, .. }, inlined)) in new_targets.into_iter().enumerate() {
+            self.targets.push(*mono_item);
+            if *inlined {
                 self.inlines.insert(i + start_index);
             }
         }
@@ -280,6 +323,7 @@
     }
 }
 
+#[instrument(skip(tcx, mode), level = "debug")]
 pub fn collect_crate_mono_items(
     tcx: TyCtxt<'_>,
     mode: MonoItemCollectionMode,
@@ -319,9 +363,10 @@
 
 // Find all non-generic items by walking the HIR. These items serve as roots to
 // start monomorphizing from.
+#[instrument(skip(tcx, mode), level = "debug")]
 fn collect_roots(tcx: TyCtxt<'_>, mode: MonoItemCollectionMode) -> Vec<MonoItem<'_>> {
     debug!("collecting roots");
-    let mut roots = Vec::new();
+    let mut roots = MonoItems { compute_inlining: false, tcx, items: Vec::new() };
 
     {
         let entry_fn = tcx.entry_fn(());
@@ -347,13 +392,17 @@
     // whose predicates hold. Luckily, items that aren't instantiable
     // can't actually be used, so we can just skip codegenning them.
     roots
+        .items
         .into_iter()
-        .filter_map(|root| root.node.is_instantiable(tcx).then_some(root.node))
+        .filter_map(|(Spanned { node: mono_item, .. }, _)| {
+            mono_item.is_instantiable(tcx).then_some(mono_item)
+        })
         .collect()
 }
 
 /// Collect all monomorphized items reachable from `starting_point`, and emit a note diagnostic if a
 /// post-monorphization error is encountered during a collection step.
+#[instrument(skip(tcx, visited, recursion_depths, recursion_limit, inlining_map), level = "debug")]
 fn collect_items_rec<'tcx>(
     tcx: TyCtxt<'tcx>,
     starting_point: Spanned<MonoItem<'tcx>>,
@@ -368,7 +417,7 @@
     }
     debug!("BEGIN collect_items_rec({})", starting_point.node);
 
-    let mut neighbors = Vec::new();
+    let mut neighbors = MonoItems { compute_inlining: true, tcx, items: Vec::new() };
     let recursion_depth_reset;
 
     //
@@ -483,10 +532,9 @@
             &format!("the above error was encountered while instantiating `{}`", formatted_item),
         );
     }
+    inlining_map.lock_mut().record_accesses(starting_point.node, &neighbors.items);
 
-    record_accesses(tcx, starting_point.node, neighbors.iter().map(|i| &i.node), inlining_map);
-
-    for neighbour in neighbors {
+    for (neighbour, _) in neighbors.items {
         collect_items_rec(tcx, neighbour, visited, recursion_depths, recursion_limit, inlining_map);
     }
 
@@ -497,25 +545,6 @@
     debug!("END collect_items_rec({})", starting_point.node);
 }
 
-fn record_accesses<'a, 'tcx: 'a>(
-    tcx: TyCtxt<'tcx>,
-    caller: MonoItem<'tcx>,
-    callees: impl Iterator<Item = &'a MonoItem<'tcx>>,
-    inlining_map: MTRef<'_, MTLock<InliningMap<'tcx>>>,
-) {
-    let is_inlining_candidate = |mono_item: &MonoItem<'tcx>| {
-        mono_item.instantiation_mode(tcx) == InstantiationMode::LocalCopy
-    };
-
-    // We collect this into a `SmallVec` to avoid calling `is_inlining_candidate` in the lock.
-    // FIXME: Call `is_inlining_candidate` when pushing to `neighbors` in `collect_items_rec`
-    // instead to avoid creating this `SmallVec`.
-    let accesses: SmallVec<[_; 128]> =
-        callees.map(|mono_item| (*mono_item, is_inlining_candidate(mono_item))).collect();
-
-    inlining_map.lock_mut().record_accesses(caller, &accesses);
-}
-
 /// Format instance name that is already known to be too long for rustc.
 /// Show only the first and last 32 characters to avoid blasting
 /// the user's terminal with thousands of lines of type-name.
@@ -627,7 +656,7 @@
 struct MirNeighborCollector<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
     body: &'a mir::Body<'tcx>,
-    output: &'a mut Vec<Spanned<MonoItem<'tcx>>>,
+    output: &'a mut MonoItems<'tcx>,
     instance: Instance<'tcx>,
 }
 
@@ -726,13 +755,15 @@
     /// This does not walk the constant, as it has been handled entirely here and trying
     /// to walk it would attempt to evaluate the `ty::Const` inside, which doesn't necessarily
     /// work, as some constants cannot be represented in the type system.
+    #[instrument(skip(self), level = "debug")]
     fn visit_constant(&mut self, constant: &mir::Constant<'tcx>, location: Location) {
         let literal = self.monomorphize(constant.literal);
         let val = match literal {
             mir::ConstantKind::Val(val, _) => val,
-            mir::ConstantKind::Ty(ct) => match ct.val() {
-                ty::ConstKind::Value(val) => val,
+            mir::ConstantKind::Ty(ct) => match ct.kind() {
+                ty::ConstKind::Value(val) => self.tcx.valtree_to_const_val((ct.ty(), val)),
                 ty::ConstKind::Unevaluated(ct) => {
+                    debug!(?ct);
                     let param_env = ty::ParamEnv::reveal_all();
                     match self.tcx.const_eval_resolve(param_env, ct, None) {
                         // The `monomorphize` call should have evaluated that constant already.
@@ -752,14 +783,18 @@
         self.visit_ty(literal.ty(), TyContext::Location(location));
     }
 
+    #[instrument(skip(self), level = "debug")]
     fn visit_const(&mut self, constant: ty::Const<'tcx>, location: Location) {
         debug!("visiting const {:?} @ {:?}", constant, location);
 
         let substituted_constant = self.monomorphize(constant);
         let param_env = ty::ParamEnv::reveal_all();
 
-        match substituted_constant.val() {
-            ty::ConstKind::Value(val) => collect_const_value(self.tcx, val, self.output),
+        match substituted_constant.kind() {
+            ty::ConstKind::Value(val) => {
+                let const_val = self.tcx.valtree_to_const_val((constant.ty(), val));
+                collect_const_value(self.tcx, const_val, self.output)
+            }
             ty::ConstKind::Unevaluated(unevaluated) => {
                 match self.tcx.const_eval_resolve(param_env, unevaluated, None) {
                     // The `monomorphize` call should have evaluated that constant already.
@@ -905,7 +940,7 @@
     ty: Ty<'tcx>,
     is_direct_call: bool,
     source: Span,
-    output: &mut Vec<Spanned<MonoItem<'tcx>>>,
+    output: &mut MonoItems<'tcx>,
 ) {
     let instance = Instance::resolve_drop_in_place(tcx, ty);
     visit_instance_use(tcx, instance, is_direct_call, source, output);
@@ -916,7 +951,7 @@
     ty: Ty<'tcx>,
     is_direct_call: bool,
     source: Span,
-    output: &mut Vec<Spanned<MonoItem<'tcx>>>,
+    output: &mut MonoItems<'tcx>,
 ) {
     if let ty::FnDef(def_id, substs) = *ty.kind() {
         let instance = if is_direct_call {
@@ -934,7 +969,7 @@
     instance: ty::Instance<'tcx>,
     is_direct_call: bool,
     source: Span,
-    output: &mut Vec<Spanned<MonoItem<'tcx>>>,
+    output: &mut MonoItems<'tcx>,
 ) {
     debug!("visit_item_use({:?}, is_direct_call={:?})", instance, is_direct_call);
     if !should_codegen_locally(tcx, &instance) {
@@ -1094,6 +1129,7 @@
     }
 }
 
+#[instrument(skip(tcx), level = "debug")]
 fn create_fn_mono_item<'tcx>(
     tcx: TyCtxt<'tcx>,
     instance: Instance<'tcx>,
@@ -1107,7 +1143,10 @@
         crate::util::dump_closure_profile(tcx, instance);
     }
 
-    respan(source, MonoItem::Fn(instance.polymorphize(tcx)))
+    let respanned = respan(source, MonoItem::Fn(instance.polymorphize(tcx)));
+    debug!(?respanned);
+
+    respanned
 }
 
 /// Creates a `MonoItem` for each method that is referenced by the vtable for
@@ -1117,7 +1156,7 @@
     trait_ty: Ty<'tcx>,
     impl_ty: Ty<'tcx>,
     source: Span,
-    output: &mut Vec<Spanned<MonoItem<'tcx>>>,
+    output: &mut MonoItems<'tcx>,
 ) {
     assert!(!trait_ty.has_escaping_bound_vars() && !impl_ty.has_escaping_bound_vars());
 
@@ -1159,7 +1198,7 @@
 struct RootCollector<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
     mode: MonoItemCollectionMode,
-    output: &'a mut Vec<Spanned<MonoItem<'tcx>>>,
+    output: &'a mut MonoItems<'tcx>,
     entry_fn: Option<(DefId, EntryFnType)>,
 }
 
@@ -1249,6 +1288,7 @@
 
     /// If `def_id` represents a root, pushes it onto the list of
     /// outputs. (Note that all roots must be monomorphic.)
+    #[instrument(skip(self), level = "debug")]
     fn push_if_root(&mut self, def_id: LocalDefId) {
         if self.is_root(def_id) {
             debug!("RootCollector::push_if_root: found root def_id={:?}", def_id);
@@ -1305,7 +1345,7 @@
 fn create_mono_items_for_default_impls<'tcx>(
     tcx: TyCtxt<'tcx>,
     item: &'tcx hir::Item<'tcx>,
-    output: &mut Vec<Spanned<MonoItem<'tcx>>>,
+    output: &mut MonoItems<'tcx>,
 ) {
     match item.kind {
         hir::ItemKind::Impl(ref impl_) => {
@@ -1361,11 +1401,7 @@
 }
 
 /// Scans the miri alloc in order to find function calls, closures, and drop-glue.
-fn collect_miri<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    alloc_id: AllocId,
-    output: &mut Vec<Spanned<MonoItem<'tcx>>>,
-) {
+fn collect_miri<'tcx>(tcx: TyCtxt<'tcx>, alloc_id: AllocId, output: &mut MonoItems<'tcx>) {
     match tcx.global_alloc(alloc_id) {
         GlobalAlloc::Static(def_id) => {
             assert!(!tcx.is_thread_local_static(def_id));
@@ -1393,21 +1429,21 @@
 }
 
 /// Scans the MIR in order to find function calls, closures, and drop-glue.
+#[instrument(skip(tcx, output), level = "debug")]
 fn collect_neighbours<'tcx>(
     tcx: TyCtxt<'tcx>,
     instance: Instance<'tcx>,
-    output: &mut Vec<Spanned<MonoItem<'tcx>>>,
+    output: &mut MonoItems<'tcx>,
 ) {
-    debug!("collect_neighbours: {:?}", instance.def_id());
     let body = tcx.instance_mir(instance.def);
-
     MirNeighborCollector { tcx, body: &body, output, instance }.visit_body(&body);
 }
 
+#[instrument(skip(tcx, output), level = "debug")]
 fn collect_const_value<'tcx>(
     tcx: TyCtxt<'tcx>,
     value: ConstValue<'tcx>,
-    output: &mut Vec<Spanned<MonoItem<'tcx>>>,
+    output: &mut MonoItems<'tcx>,
 ) {
     match value {
         ConstValue::Scalar(Scalar::Ptr(ptr, _size)) => collect_miri(tcx, ptr.provenance, output),
diff --git a/compiler/rustc_monomorphize/src/lib.rs b/compiler/rustc_monomorphize/src/lib.rs
index f0333d6..ef4560b 100644
--- a/compiler/rustc_monomorphize/src/lib.rs
+++ b/compiler/rustc_monomorphize/src/lib.rs
@@ -1,5 +1,4 @@
 #![feature(array_windows)]
-#![feature(crate_visibility_modifier)]
 #![feature(control_flow_enum)]
 #![feature(let_else)]
 #![recursion_limit = "256"]
diff --git a/compiler/rustc_monomorphize/src/polymorphize.rs b/compiler/rustc_monomorphize/src/polymorphize.rs
index 3cfd935..f29143b 100644
--- a/compiler/rustc_monomorphize/src/polymorphize.rs
+++ b/compiler/rustc_monomorphize/src/polymorphize.rs
@@ -13,7 +13,7 @@
 };
 use rustc_middle::ty::{
     self,
-    fold::{TypeFoldable, TypeVisitor},
+    fold::{TypeFoldable, TypeSuperFoldable, TypeVisitor},
     query::Providers,
     subst::SubstsRef,
     Const, Ty, TyCtxt,
@@ -283,7 +283,7 @@
             return ControlFlow::CONTINUE;
         }
 
-        match c.val() {
+        match c.kind() {
             ty::ConstKind::Param(param) => {
                 debug!(?param);
                 self.unused_parameters.clear(param.index);
@@ -353,7 +353,7 @@
             return ControlFlow::CONTINUE;
         }
 
-        match c.val() {
+        match c.kind() {
             ty::ConstKind::Param(param) => {
                 if self.unused_parameters.contains(param.index).unwrap_or(false) {
                     ControlFlow::CONTINUE
diff --git a/compiler/rustc_monomorphize/src/util.rs b/compiler/rustc_monomorphize/src/util.rs
index 04baa01..d3aaad4 100644
--- a/compiler/rustc_monomorphize/src/util.rs
+++ b/compiler/rustc_monomorphize/src/util.rs
@@ -7,7 +7,7 @@
 ///
 /// During the same compile all closures dump the information in the same file
 /// "closure_profile_XXXXX.csv", which is created in the directory where the compiler is invoked.
-crate fn dump_closure_profile<'tcx>(tcx: TyCtxt<'tcx>, closure_instance: Instance<'tcx>) {
+pub(crate) fn dump_closure_profile<'tcx>(tcx: TyCtxt<'tcx>, closure_instance: Instance<'tcx>) {
     let Ok(mut file) = OpenOptions::new()
         .create(true)
         .append(true)
diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs
index ee54dd4..e9701ec 100644
--- a/compiler/rustc_parse/src/lexer/mod.rs
+++ b/compiler/rustc_parse/src/lexer/mod.rs
@@ -31,7 +31,7 @@
     pub candidate_span: Option<Span>,
 }
 
-crate fn parse_token_trees<'a>(
+pub(crate) fn parse_token_trees<'a>(
     sess: &'a ParseSess,
     src: &'a str,
     start_pos: BytePos,
diff --git a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
index bec4561..2738278 100644
--- a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
+++ b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
@@ -105,7 +105,7 @@
                     handler.span_suggestion(
                         span,
                         "consider removing the non-printing characters",
-                        ch.to_string(),
+                        ch,
                         Applicability::MaybeIncorrect,
                     );
                 }
@@ -141,7 +141,7 @@
                 .span_suggestion(
                     char_span,
                     "escape the character",
-                    c.escape_default().to_string(),
+                    c.escape_default(),
                     Applicability::MachineApplicable,
                 )
                 .emit();
@@ -157,7 +157,7 @@
                 .span_suggestion(
                     span,
                     "escape the character",
-                    "\\r".to_string(),
+                    "\\r",
                     Applicability::MachineApplicable,
                 )
                 .emit();
@@ -299,7 +299,7 @@
                 .span_suggestion_verbose(
                     span.shrink_to_hi(),
                     "terminate the unicode escape",
-                    "}".to_string(),
+                    "}",
                     Applicability::MaybeIncorrect,
                 )
                 .emit();
diff --git a/compiler/rustc_parse/src/lexer/unicode_chars.rs b/compiler/rustc_parse/src/lexer/unicode_chars.rs
index faa686c..2c68cc5 100644
--- a/compiler/rustc_parse/src/lexer/unicode_chars.rs
+++ b/compiler/rustc_parse/src/lexer/unicode_chars.rs
@@ -369,7 +369,7 @@
             "Unicode character '{}' ({}) looks like '{}' ({}), but it is not",
             ch, u_name, ascii_char, ascii_name
         );
-        err.span_suggestion(span, &msg, ascii_char.to_string(), Applicability::MaybeIncorrect);
+        err.span_suggestion(span, &msg, ascii_char, Applicability::MaybeIncorrect);
     }
     token.clone()
 }
diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs
index 423cddd..f3bdd63 100644
--- a/compiler/rustc_parse/src/lib.rs
+++ b/compiler/rustc_parse/src/lib.rs
@@ -2,7 +2,6 @@
 
 #![feature(array_windows)]
 #![feature(box_patterns)]
-#![feature(crate_visibility_modifier)]
 #![feature(if_let_guard)]
 #![feature(let_chains)]
 #![feature(let_else)]
@@ -13,20 +12,16 @@
 extern crate tracing;
 
 use rustc_ast as ast;
-use rustc_ast::token::{self, Nonterminal, Token, TokenKind};
-use rustc_ast::tokenstream::{self, AttributesData, CanSynthesizeMissingTokens, LazyTokenStream};
-use rustc_ast::tokenstream::{AttrAnnotatedTokenStream, AttrAnnotatedTokenTree};
-use rustc_ast::tokenstream::{Spacing, TokenStream};
+use rustc_ast::token;
+use rustc_ast::tokenstream::TokenStream;
 use rustc_ast::Attribute;
 use rustc_ast::{AttrItem, MetaItem};
-use rustc_ast::{HasAttrs, HasSpan, HasTokens};
-use rustc_ast_pretty::pprust::{self, AstPrettyPrint};
+use rustc_ast_pretty::pprust;
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::{Applicability, Diagnostic, FatalError, Level, PResult};
 use rustc_session::parse::ParseSess;
 use rustc_span::{FileName, SourceFile, Span};
 
-use std::fmt;
 use std::path::Path;
 
 pub const MACRO_ARGUMENTS: Option<&str> = Some("macro arguments");
@@ -241,111 +236,10 @@
     Ok(result)
 }
 
-// NOTE(Centril): The following probably shouldn't be here but it acknowledges the
-// fact that architecturally, we are using parsing (read on below to understand why).
-
-pub fn to_token_stream(
-    node: &(impl HasAttrs + HasSpan + HasTokens + AstPrettyPrint + fmt::Debug),
-    sess: &ParseSess,
-    synthesize_tokens: CanSynthesizeMissingTokens,
-) -> TokenStream {
-    if let Some(tokens) = prepend_attrs(&node.attrs(), node.tokens()) {
-        return tokens;
-    } else if matches!(synthesize_tokens, CanSynthesizeMissingTokens::Yes) {
-        return fake_token_stream(sess, node);
-    } else {
-        panic!("Missing tokens for nt {:?} at {:?}: {:?}", node, node.span(), node.pretty_print());
-    }
-}
-
-pub fn nt_to_tokenstream(
-    nt: &Nonterminal,
-    sess: &ParseSess,
-    synthesize_tokens: CanSynthesizeMissingTokens,
-) -> TokenStream {
-    // A `Nonterminal` is often a parsed AST item. At this point we now
-    // need to convert the parsed AST to an actual token stream, e.g.
-    // un-parse it basically.
-    //
-    // Unfortunately there's not really a great way to do that in a
-    // guaranteed lossless fashion right now. The fallback here is to just
-    // stringify the AST node and reparse it, but this loses all span
-    // information.
-    //
-    // As a result, some AST nodes are annotated with the token stream they
-    // came from. Here we attempt to extract these lossless token streams
-    // before we fall back to the stringification.
-
-    let convert_tokens =
-        |tokens: Option<&LazyTokenStream>| Some(tokens?.create_token_stream().to_tokenstream());
-
-    let tokens = match *nt {
-        Nonterminal::NtItem(ref item) => prepend_attrs(&item.attrs, item.tokens.as_ref()),
-        Nonterminal::NtBlock(ref block) => convert_tokens(block.tokens.as_ref()),
-        Nonterminal::NtStmt(ref stmt) if let ast::StmtKind::Empty = stmt.kind => {
-            let tokens = AttrAnnotatedTokenStream::new(vec![(
-                tokenstream::AttrAnnotatedTokenTree::Token(Token::new(
-                    TokenKind::Semi,
-                    stmt.span,
-                )),
-                Spacing::Alone,
-            )]);
-            prepend_attrs(&stmt.attrs(), Some(&LazyTokenStream::new(tokens)))
-        }
-        Nonterminal::NtStmt(ref stmt) => prepend_attrs(&stmt.attrs(), stmt.tokens()),
-        Nonterminal::NtPat(ref pat) => convert_tokens(pat.tokens.as_ref()),
-        Nonterminal::NtTy(ref ty) => convert_tokens(ty.tokens.as_ref()),
-        Nonterminal::NtIdent(ident, is_raw) => {
-            Some(tokenstream::TokenTree::token(token::Ident(ident.name, is_raw), ident.span).into())
-        }
-        Nonterminal::NtLifetime(ident) => {
-            Some(tokenstream::TokenTree::token(token::Lifetime(ident.name), ident.span).into())
-        }
-        Nonterminal::NtMeta(ref attr) => convert_tokens(attr.tokens.as_ref()),
-        Nonterminal::NtPath(ref path) => convert_tokens(path.tokens.as_ref()),
-        Nonterminal::NtVis(ref vis) => convert_tokens(vis.tokens.as_ref()),
-        Nonterminal::NtExpr(ref expr) | Nonterminal::NtLiteral(ref expr) => {
-            prepend_attrs(&expr.attrs, expr.tokens.as_ref())
-        }
-    };
-
-    if let Some(tokens) = tokens {
-        return tokens;
-    } else if matches!(synthesize_tokens, CanSynthesizeMissingTokens::Yes) {
-        return nt_fake_token_stream(sess, nt);
-    } else {
-        panic!(
-            "Missing tokens for nt {:?} at {:?}: {:?}",
-            nt,
-            nt.span(),
-            pprust::nonterminal_to_string(nt)
-        );
-    }
-}
-
-fn prepend_attrs(attrs: &[Attribute], tokens: Option<&LazyTokenStream>) -> Option<TokenStream> {
-    let tokens = tokens?;
-    if attrs.is_empty() {
-        return Some(tokens.create_token_stream().to_tokenstream());
-    }
-    let attr_data = AttributesData { attrs: attrs.to_vec().into(), tokens: tokens.clone() };
-    let wrapped = AttrAnnotatedTokenStream::new(vec![(
-        AttrAnnotatedTokenTree::Attributes(attr_data),
-        Spacing::Alone,
-    )]);
-    Some(wrapped.to_tokenstream())
-}
-
-pub fn fake_token_stream(sess: &ParseSess, node: &(impl AstPrettyPrint + HasSpan)) -> TokenStream {
-    let source = node.pretty_print();
+pub fn fake_token_stream_for_item(sess: &ParseSess, item: &ast::Item) -> TokenStream {
+    let source = pprust::item_to_string(item);
     let filename = FileName::macro_expansion_source_code(&source);
-    parse_stream_from_source_str(filename, source, sess, Some(node.span()))
-}
-
-fn nt_fake_token_stream(sess: &ParseSess, nt: &Nonterminal) -> TokenStream {
-    let source = pprust::nonterminal_to_string(nt);
-    let filename = FileName::macro_expansion_source_code(&source);
-    parse_stream_from_source_str(filename, source, sess, Some(nt.span()))
+    parse_stream_from_source_str(filename, source, sess, Some(item.span))
 }
 
 pub fn fake_token_stream_for_crate(sess: &ParseSess, krate: &ast::Crate) -> TokenStream {
@@ -388,7 +282,7 @@
         .span_suggestion(
             span,
             "missing condition and attribute",
-            CFG_ATTR_GRAMMAR_HELP.to_string(),
+            CFG_ATTR_GRAMMAR_HELP,
             Applicability::HasPlaceholders,
         )
         .note(CFG_ATTR_NOTE_REF)
diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs
index 2f90a7c..acdbddf 100644
--- a/compiler/rustc_parse/src/parser/attr.rs
+++ b/compiler/rustc_parse/src/parser/attr.rs
@@ -78,7 +78,7 @@
                         err.span_suggestion_verbose(
                             replacement_span,
                             "you might have meant to write a regular comment",
-                            String::new(),
+                            "",
                             rustc_errors::Applicability::MachineApplicable,
                         );
                     }
@@ -200,12 +200,11 @@
                         item.kind.descr(),
                         attr_name
                     ),
-                    (match attr_type {
+                    match attr_type {
                         OuterAttributeType::Attribute => "",
                         OuterAttributeType::DocBlockComment => "*",
                         OuterAttributeType::DocComment => "/",
-                    })
-                    .to_string(),
+                    },
                     rustc_errors::Applicability::MachineApplicable,
                 );
                 return None;
@@ -284,7 +283,7 @@
     /// terminated by a semicolon.
     ///
     /// Matches `inner_attrs*`.
-    crate fn parse_inner_attributes(&mut self) -> PResult<'a, Vec<ast::Attribute>> {
+    pub(crate) fn parse_inner_attributes(&mut self) -> PResult<'a, Vec<ast::Attribute>> {
         let mut attrs: Vec<ast::Attribute> = vec![];
         loop {
             let start_pos: u32 = self.token_cursor.num_next_calls.try_into().unwrap();
@@ -322,7 +321,7 @@
         Ok(attrs)
     }
 
-    crate fn parse_unsuffixed_lit(&mut self) -> PResult<'a, ast::Lit> {
+    pub(crate) fn parse_unsuffixed_lit(&mut self) -> PResult<'a, ast::Lit> {
         let lit = self.parse_lit()?;
         debug!("checking if {:?} is unusuffixed", lit);
 
@@ -358,7 +357,7 @@
     }
 
     /// Matches `COMMASEP(meta_item_inner)`.
-    crate fn parse_meta_seq_top(&mut self) -> PResult<'a, Vec<ast::NestedMetaItem>> {
+    pub(crate) fn parse_meta_seq_top(&mut self) -> PResult<'a, Vec<ast::NestedMetaItem>> {
         // Presumably, the majority of the time there will only be one attr.
         let mut nmis = Vec::with_capacity(1);
         while self.token.kind != token::Eof {
@@ -401,7 +400,7 @@
         Ok(ast::MetaItem { path, kind, span })
     }
 
-    crate fn parse_meta_item_kind(&mut self) -> PResult<'a, ast::MetaItemKind> {
+    pub(crate) fn parse_meta_item_kind(&mut self) -> PResult<'a, ast::MetaItemKind> {
         Ok(if self.eat(&token::Eq) {
             ast::MetaItemKind::NameValue(self.parse_unsuffixed_lit()?)
         } else if self.check(&token::OpenDelim(Delimiter::Parenthesis)) {
diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index 369650e..ba325d7 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -1,8 +1,7 @@
 use super::pat::Expected;
-use super::ty::{AllowPlus, RecoverQuestionMark};
 use super::{
-    BlockMode, CommaRecoveryMode, Parser, PathStyle, RecoverColon, RecoverComma, Restrictions,
-    SemiColonMode, SeqSep, TokenExpectType, TokenType,
+    BlockMode, CommaRecoveryMode, Parser, PathStyle, Restrictions, SemiColonMode, SeqSep,
+    TokenExpectType, TokenType,
 };
 
 use crate::lexer::UnmatchedBrace;
@@ -17,11 +16,11 @@
 };
 use rustc_ast_pretty::pprust;
 use rustc_data_structures::fx::FxHashSet;
-use rustc_errors::{pluralize, struct_span_err, Diagnostic, EmissionGuarantee, ErrorGuaranteed};
 use rustc_errors::{
-    Applicability, DiagnosticBuilder, DiagnosticMessage, Handler, MultiSpan, PResult,
+    fluent, Applicability, DiagnosticBuilder, DiagnosticMessage, Handler, MultiSpan, PResult,
 };
-use rustc_macros::SessionDiagnostic;
+use rustc_errors::{pluralize, struct_span_err, Diagnostic, EmissionGuarantee, ErrorGuaranteed};
+use rustc_macros::{SessionDiagnostic, SessionSubdiagnostic};
 use rustc_span::source_map::Spanned;
 use rustc_span::symbol::{kw, Ident};
 use rustc_span::{Span, SpanSnippetError, DUMMY_SP};
@@ -29,6 +28,7 @@
 
 use std::mem::take;
 
+use crate::parser;
 use tracing::{debug, trace};
 
 const TURBOFISH_SUGGESTION_STR: &str =
@@ -132,7 +132,7 @@
 }
 
 /// Control whether the closing delimiter should be consumed when calling `Parser::consume_block`.
-crate enum ConsumeClosingDelim {
+pub(crate) enum ConsumeClosingDelim {
     Yes,
     No,
 }
@@ -252,10 +252,92 @@
     pub span: Span,
 }
 
+#[derive(SessionDiagnostic)]
+#[error(code = "E0178", slug = "parser-maybe-recover-from-bad-type-plus")]
+struct BadTypePlus {
+    pub ty: String,
+    #[primary_span]
+    pub span: Span,
+    #[subdiagnostic]
+    pub sub: BadTypePlusSub,
+}
+
+#[derive(SessionSubdiagnostic)]
+pub enum BadTypePlusSub {
+    #[suggestion(
+        slug = "parser-add-paren",
+        code = "{sum_with_parens}",
+        applicability = "machine-applicable"
+    )]
+    AddParen {
+        sum_with_parens: String,
+        #[primary_span]
+        span: Span,
+    },
+    #[label(slug = "parser-forgot-paren")]
+    ForgotParen {
+        #[primary_span]
+        span: Span,
+    },
+    #[label(slug = "parser-expect-path")]
+    ExpectPath {
+        #[primary_span]
+        span: Span,
+    },
+}
+
+#[derive(SessionDiagnostic)]
+#[error(slug = "parser-maybe-recover-from-bad-qpath-stage-2")]
+struct BadQPathStage2 {
+    #[primary_span]
+    #[suggestion(applicability = "maybe-incorrect")]
+    span: Span,
+    ty: String,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(slug = "parser-incorrect-semicolon")]
+struct IncorrectSemicolon<'a> {
+    #[primary_span]
+    #[suggestion_short(applicability = "machine-applicable")]
+    span: Span,
+    #[help]
+    opt_help: Option<()>,
+    name: &'a str,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(slug = "parser-incorrect-use-of-await")]
+struct IncorrectUseOfAwait {
+    #[primary_span]
+    #[suggestion(message = "parentheses-suggestion", applicability = "machine-applicable")]
+    span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(slug = "parser-incorrect-use-of-await")]
+struct IncorrectAwait {
+    #[primary_span]
+    span: Span,
+    #[suggestion(message = "postfix-suggestion", code = "{expr}.await{question_mark}")]
+    sugg_span: (Span, Applicability),
+    expr: String,
+    question_mark: &'static str,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(slug = "parser-in-in-typo")]
+struct InInTypo {
+    #[primary_span]
+    span: Span,
+    #[suggestion(applicability = "machine-applicable")]
+    sugg_span: Span,
+}
+
 // SnapshotParser is used to create a snapshot of the parser
 // without causing duplicate errors being emitted when the `Parser`
 // is dropped.
-pub(super) struct SnapshotParser<'a> {
+pub struct SnapshotParser<'a> {
     parser: Parser<'a>,
     unclosed_delims: Vec<UnmatchedBrace>,
 }
@@ -311,7 +393,7 @@
     }
 
     /// Create a snapshot of the `Parser`.
-    pub(super) fn create_snapshot_for_diagnostic(&self) -> SnapshotParser<'a> {
+    pub fn create_snapshot_for_diagnostic(&self) -> SnapshotParser<'a> {
         let mut snapshot = self.clone();
         let unclosed_delims = self.unclosed_delims.clone();
         // Clear `unclosed_delims` in snapshot to avoid
@@ -350,7 +432,7 @@
                 err.span_suggestion_verbose(
                     ident.span.shrink_to_lo(),
                     &format!("escape `{}` to use it as an identifier", ident.name),
-                    "r#".to_owned(),
+                    "r#",
                     Applicability::MaybeIncorrect,
                 );
             }
@@ -364,7 +446,7 @@
                 err.span_suggestion(
                     self.token.span,
                     "remove this comma",
-                    String::new(),
+                    "",
                     Applicability::MachineApplicable,
                 );
             }
@@ -400,6 +482,35 @@
             .map(|x| TokenType::Token(x.clone()))
             .chain(inedible.iter().map(|x| TokenType::Token(x.clone())))
             .chain(self.expected_tokens.iter().cloned())
+            .filter_map(|token| {
+                // filter out suggestions which suggest the same token which was found and deemed incorrect
+                fn is_ident_eq_keyword(found: &TokenKind, expected: &TokenType) -> bool {
+                    if let TokenKind::Ident(current_sym, _) = found {
+                        if let TokenType::Keyword(suggested_sym) = expected {
+                            return current_sym == suggested_sym;
+                        }
+                    }
+                    false
+                }
+                if token != parser::TokenType::Token(self.token.kind.clone()) {
+                    let eq = is_ident_eq_keyword(&self.token.kind, &token);
+                    // if the suggestion is a keyword and the found token is an ident,
+                    // the content of which are equal to the suggestion's content,
+                    // we can remove that suggestion (see the return None statement below)
+
+                    // if this isn't the case however, and the suggestion is a token the
+                    // content of which is the same as the found token's, we remove it as well
+                    if !eq {
+                        if let TokenType::Token(kind) = &token {
+                            if kind == &self.token.kind {
+                                return None;
+                            }
+                        }
+                        return Some(token);
+                    }
+                }
+                return None;
+            })
             .collect::<Vec<_>>();
         expected.sort_by_cached_key(|x| x.to_string());
         expected.dedup();
@@ -437,7 +548,7 @@
                 self.bump();
                 let sp = self.prev_token.span;
                 self.struct_span_err(sp, &msg)
-                    .span_suggestion_short(sp, "change this to `;`", ";".to_string(), appl)
+                    .span_suggestion_short(sp, "change this to `;`", ";", appl)
                     .emit();
                 return Ok(true);
             } else if self.look_ahead(0, |t| {
@@ -456,7 +567,7 @@
                 let sp = self.prev_token.span.shrink_to_hi();
                 self.struct_span_err(sp, &msg)
                     .span_label(self.token.span, "unexpected token")
-                    .span_suggestion_short(sp, "add `;` here", ";".to_string(), appl)
+                    .span_suggestion_short(sp, "add `;` here", ";", appl)
                     .emit();
                 return Ok(true);
             }
@@ -583,7 +694,7 @@
                 err.span_suggestion(
                     span,
                     &format!("remove the extra `#`{}", pluralize!(count)),
-                    String::new(),
+                    "",
                     Applicability::MachineApplicable,
                 );
                 err.span_label(
@@ -624,13 +735,10 @@
                     err.delay_as_bug();
                     self.struct_span_err(
                         expr.span,
-                        DiagnosticMessage::fluent("parser-struct-literal-body-without-path"),
+                        fluent::parser::struct_literal_body_without_path,
                     )
                     .multipart_suggestion(
-                        DiagnosticMessage::fluent_attr(
-                            "parser-struct-literal-body-without-path",
-                            "suggestion",
-                        ),
+                        fluent::parser::suggestion,
                         vec![
                             (expr.span.shrink_to_lo(), "{ SomeStruct ".to_string()),
                             (expr.span.shrink_to_hi(), " }".to_string()),
@@ -683,7 +791,7 @@
                 err.span_suggestion(
                     sp,
                     "maybe write a path separator here",
-                    "::".to_string(),
+                    "::",
                     if allow_unstable {
                         Applicability::MaybeIncorrect
                     } else {
@@ -695,7 +803,7 @@
                 err.span_suggestion(
                     sp,
                     "try using a semicolon",
-                    ";".to_string(),
+                    ";",
                     Applicability::MaybeIncorrect,
                 );
             } else if allow_unstable {
@@ -839,7 +947,7 @@
             .span_suggestion(
                 span,
                 &format!("remove extra angle bracket{}", pluralize!(total_num_of_gt)),
-                String::new(),
+                "",
                 Applicability::MachineApplicable,
             )
             .emit();
@@ -921,7 +1029,7 @@
                         e.span_suggestion_verbose(
                             binop.span.shrink_to_lo(),
                             TURBOFISH_SUGGESTION_STR,
-                            "::".to_string(),
+                            "::",
                             Applicability::MaybeIncorrect,
                         )
                         .emit();
@@ -1080,7 +1188,7 @@
                     err.span_suggestion_verbose(
                         op.span.shrink_to_lo(),
                         TURBOFISH_SUGGESTION_STR,
-                        "::".to_string(),
+                        "::",
                         Applicability::MaybeIncorrect,
                     );
                 };
@@ -1202,26 +1310,14 @@
         }
     }
 
-    pub(super) fn maybe_report_ambiguous_plus(
-        &mut self,
-        allow_plus: AllowPlus,
-        impl_dyn_multi: bool,
-        ty: &Ty,
-    ) {
-        if matches!(allow_plus, AllowPlus::No) && impl_dyn_multi {
+    pub(super) fn maybe_report_ambiguous_plus(&mut self, impl_dyn_multi: bool, ty: &Ty) {
+        if impl_dyn_multi {
             self.sess.emit_err(AmbiguousPlus { sum_ty: pprust::ty_to_string(&ty), span: ty.span });
         }
     }
 
     /// Swift lets users write `Ty?` to mean `Option<Ty>`. Parse the construct and recover from it.
-    pub(super) fn maybe_recover_from_question_mark(
-        &mut self,
-        ty: P<Ty>,
-        recover_question_mark: RecoverQuestionMark,
-    ) -> P<Ty> {
-        if let RecoverQuestionMark::No = recover_question_mark {
-            return ty;
-        }
+    pub(super) fn maybe_recover_from_question_mark(&mut self, ty: P<Ty>) -> P<Ty> {
         if self.token == token::Question {
             self.bump();
             self.struct_span_err(self.prev_token.span, "invalid `?` in type")
@@ -1241,13 +1337,9 @@
         }
     }
 
-    pub(super) fn maybe_recover_from_bad_type_plus(
-        &mut self,
-        allow_plus: AllowPlus,
-        ty: &Ty,
-    ) -> PResult<'a, ()> {
+    pub(super) fn maybe_recover_from_bad_type_plus(&mut self, ty: &Ty) -> PResult<'a, ()> {
         // Do not add `+` to expected tokens.
-        if matches!(allow_plus, AllowPlus::No) || !self.token.is_like_plus() {
+        if !self.token.is_like_plus() {
             return Ok(());
         }
 
@@ -1255,15 +1347,7 @@
         let bounds = self.parse_generic_bounds(None)?;
         let sum_span = ty.span.to(self.prev_token.span);
 
-        let mut err = struct_span_err!(
-            self.sess.span_diagnostic,
-            sum_span,
-            E0178,
-            "expected a path on the left-hand side of `+`, not `{}`",
-            pprust::ty_to_string(ty)
-        );
-
-        match ty.kind {
+        let sub = match ty.kind {
             TyKind::Rptr(ref lifetime, ref mut_ty) => {
                 let sum_with_parens = pprust::to_string(|s| {
                     s.s.word("&");
@@ -1271,24 +1355,21 @@
                     s.print_mutability(mut_ty.mutbl, false);
                     s.popen();
                     s.print_type(&mut_ty.ty);
-                    s.print_type_bounds(" +", &bounds);
+                    if !bounds.is_empty() {
+                        s.word(" + ");
+                        s.print_type_bounds(&bounds);
+                    }
                     s.pclose()
                 });
-                err.span_suggestion(
-                    sum_span,
-                    "try adding parentheses",
-                    sum_with_parens,
-                    Applicability::MachineApplicable,
-                );
+
+                BadTypePlusSub::AddParen { sum_with_parens, span: sum_span }
             }
-            TyKind::Ptr(..) | TyKind::BareFn(..) => {
-                err.span_label(sum_span, "perhaps you forgot parentheses?");
-            }
-            _ => {
-                err.span_label(sum_span, "expected a path");
-            }
-        }
-        err.emit();
+            TyKind::Ptr(..) | TyKind::BareFn(..) => BadTypePlusSub::ForgotParen { span: sum_span },
+            _ => BadTypePlusSub::ExpectPath { span: sum_span },
+        };
+
+        self.sess.emit_err(BadTypePlus { ty: pprust::ty_to_string(ty), span: sum_span, sub });
+
         Ok(())
     }
 
@@ -1427,10 +1508,9 @@
     pub(super) fn maybe_recover_from_bad_qpath<T: RecoverQPath>(
         &mut self,
         base: P<T>,
-        allow_recovery: bool,
     ) -> PResult<'a, P<T>> {
         // Do not add `::` to expected tokens.
-        if allow_recovery && self.token == token::ModSep {
+        if self.token == token::ModSep {
             if let Some(ty) = base.to_ty() {
                 return self.maybe_recover_from_bad_qpath_stage_2(ty.span, ty);
             }
@@ -1452,15 +1532,10 @@
         path.span = ty_span.to(self.prev_token.span);
 
         let ty_str = self.span_to_snippet(ty_span).unwrap_or_else(|_| pprust::ty_to_string(&ty));
-        self.struct_span_err(path.span, "missing angle brackets in associated item path")
-            .span_suggestion(
-                // This is a best-effort recovery.
-                path.span,
-                "try",
-                format!("<{}>::{}", ty_str, pprust::path_to_string(&path)),
-                Applicability::MaybeIncorrect,
-            )
-            .emit();
+        self.sess.emit_err(BadQPathStage2 {
+            span: path.span,
+            ty: format!("<{}>::{}", ty_str, pprust::path_to_string(&path)),
+        });
 
         let path_span = ty_span.shrink_to_hi(); // Use an empty path since `position == 0`.
         Ok(P(T::recovered(Some(QSelf { ty, path_span, position: 0 }), path)))
@@ -1469,13 +1544,10 @@
     pub fn maybe_consume_incorrect_semicolon(&mut self, items: &[P<Item>]) -> bool {
         if self.token.kind == TokenKind::Semi {
             self.bump();
-            let mut err = self.struct_span_err(self.prev_token.span, "expected item, found `;`");
-            err.span_suggestion_short(
-                self.prev_token.span,
-                "remove this semicolon",
-                String::new(),
-                Applicability::MachineApplicable,
-            );
+
+            let mut err =
+                IncorrectSemicolon { span: self.prev_token.span, opt_help: None, name: "" };
+
             if !items.is_empty() {
                 let previous_item = &items[items.len() - 1];
                 let previous_item_kind_name = match previous_item.kind {
@@ -1488,10 +1560,11 @@
                     _ => None,
                 };
                 if let Some(name) = previous_item_kind_name {
-                    err.help(&format!("{name} declarations are not followed by a semicolon"));
+                    err.opt_help = Some(());
+                    err.name = name;
                 }
             }
-            err.emit();
+            self.sess.emit_err(err);
             true
         } else {
             false
@@ -1576,7 +1649,7 @@
             _ => ExprKind::Await(expr),
         };
         let expr = self.mk_expr(lo.to(sp), kind, attrs);
-        self.maybe_recover_from_bad_qpath(expr, true)
+        self.maybe_recover_from_bad_qpath(expr)
     }
 
     fn recover_await_macro(&mut self) -> PResult<'a, (Span, P<Expr>, bool)> {
@@ -1605,18 +1678,20 @@
     }
 
     fn error_on_incorrect_await(&self, lo: Span, hi: Span, expr: &Expr, is_question: bool) -> Span {
-        let expr_str =
-            self.span_to_snippet(expr.span).unwrap_or_else(|_| pprust::expr_to_string(&expr));
-        let suggestion = format!("{}.await{}", expr_str, if is_question { "?" } else { "" });
-        let sp = lo.to(hi);
-        let app = match expr.kind {
+        let span = lo.to(hi);
+        let applicability = match expr.kind {
             ExprKind::Try(_) => Applicability::MaybeIncorrect, // `await <expr>?`
             _ => Applicability::MachineApplicable,
         };
-        self.struct_span_err(sp, "incorrect use of `await`")
-            .span_suggestion(sp, "`await` is a postfix operation", suggestion, app)
-            .emit();
-        sp
+
+        self.sess.emit_err(IncorrectAwait {
+            span,
+            sugg_span: (span, applicability),
+            expr: self.span_to_snippet(expr.span).unwrap_or_else(|_| pprust::expr_to_string(&expr)),
+            question_mark: if is_question { "?" } else { "" },
+        });
+
+        span
     }
 
     /// If encountering `future.await()`, consumes and emits an error.
@@ -1627,16 +1702,10 @@
             // future.await()
             let lo = self.token.span;
             self.bump(); // (
-            let sp = lo.to(self.token.span);
+            let span = lo.to(self.token.span);
             self.bump(); // )
-            self.struct_span_err(sp, "incorrect use of `await`")
-                .span_suggestion(
-                    sp,
-                    "`await` is not a method call, remove the parentheses",
-                    String::new(),
-                    Applicability::MachineApplicable,
-                )
-                .emit();
+
+            self.sess.emit_err(IncorrectUseOfAwait { span });
         }
     }
 
@@ -1665,7 +1734,7 @@
                     Applicability::MachineApplicable,
                 );
             }
-            err.span_suggestion(lo.shrink_to_lo(), &format!("{prefix}you can still access the deprecated `try!()` macro using the \"raw identifier\" syntax"), "r#".to_string(), Applicability::MachineApplicable);
+            err.span_suggestion(lo.shrink_to_lo(), &format!("{prefix}you can still access the deprecated `try!()` macro using the \"raw identifier\" syntax"), "r#", Applicability::MachineApplicable);
             err.emit();
             Ok(self.mk_expr_err(lo.to(hi)))
         } else {
@@ -1908,14 +1977,10 @@
     pub(super) fn check_for_for_in_in_typo(&mut self, in_span: Span) {
         if self.eat_keyword(kw::In) {
             // a common typo: `for _ in in bar {}`
-            self.struct_span_err(self.prev_token.span, "expected iterable, found keyword `in`")
-                .span_suggestion_short(
-                    in_span.until(self.prev_token.span),
-                    "remove the duplicated `in`",
-                    String::new(),
-                    Applicability::MachineApplicable,
-                )
-                .emit();
+            self.sess.emit_err(InInTypo {
+                span: self.prev_token.span,
+                sugg_span: in_span.until(self.prev_token.span),
+            });
         }
     }
 
@@ -1965,7 +2030,7 @@
             err.span_suggestion(
                 span,
                 "declare the type after the parameter binding",
-                String::from("<identifier>: <type>"),
+                "<identifier>: <type>",
                 Applicability::HasPlaceholders,
             );
             return Some(ident);
@@ -1980,9 +2045,9 @@
                 match pat.kind {
                     PatKind::Ident(_, ident, _) => (
                         ident,
-                        "self: ".to_string(),
+                        "self: ",
                         ": TypeName".to_string(),
-                        "_: ".to_string(),
+                        "_: ",
                         pat.span.shrink_to_lo(),
                         pat.span.shrink_to_hi(),
                         pat.span.shrink_to_lo(),
@@ -1996,9 +2061,9 @@
                                 let mutab = mutab.prefix_str();
                                 (
                                     ident,
-                                    "self: ".to_string(),
+                                    "self: ",
                                     format!("{ident}: &{mutab}TypeName"),
-                                    "_: ".to_string(),
+                                    "_: ",
                                     pat.span.shrink_to_lo(),
                                     pat.span,
                                     pat.span.shrink_to_lo(),
@@ -2070,7 +2135,7 @@
         .span_suggestion_short(
             pat.span,
             "give this argument a name or use an underscore to ignore it",
-            "_".to_owned(),
+            "_",
             Applicability::MachineApplicable,
         )
         .emit();
@@ -2304,7 +2369,7 @@
             err.span_suggestion_verbose(
                 start.until(self.token.span),
                 "the `const` keyword is only needed in the definition of the type",
-                String::new(),
+                "",
                 Applicability::MaybeIncorrect,
             );
             err.emit();
@@ -2362,7 +2427,7 @@
                     err.span_suggestion(
                         snapshot.token.span,
                         "if you meant to use an associated type binding, replace `==` with `=`",
-                        "=".to_string(),
+                        "=",
                         Applicability::MaybeIncorrect,
                     );
                     let value = self.mk_expr_err(start.to(expr.span));
@@ -2376,7 +2441,7 @@
                     err.span_suggestion(
                         snapshot.token.span,
                         "write a path separator here",
-                        "::".to_string(),
+                        "::",
                         Applicability::MaybeIncorrect,
                     );
                     err.emit();
@@ -2429,7 +2494,7 @@
         err.span_suggestion_verbose(
             move_async_span,
             "try switching the order",
-            "async move".to_owned(),
+            "async move",
             Applicability::MaybeIncorrect,
         );
         err
@@ -2437,13 +2502,12 @@
 
     /// Some special error handling for the "top-level" patterns in a match arm,
     /// `for` loop, `let`, &c. (in contrast to subpatterns within such).
-    crate fn maybe_recover_colon_colon_in_pat_typo(
+    pub(crate) fn maybe_recover_colon_colon_in_pat_typo(
         &mut self,
         mut first_pat: P<Pat>,
-        ra: RecoverColon,
         expected: Expected,
     ) -> P<Pat> {
-        if RecoverColon::Yes != ra || token::Colon != self.token.kind {
+        if token::Colon != self.token.kind {
             return first_pat;
         }
         if !matches!(first_pat.kind, PatKind::Ident(_, _, None) | PatKind::Path(..))
@@ -2535,7 +2599,7 @@
                             err.span_suggestion(
                                 span,
                                 "maybe write a path separator here",
-                                "::".to_string(),
+                                "::",
                                 Applicability::MaybeIncorrect,
                             );
                         } else {
@@ -2553,7 +2617,7 @@
         first_pat
     }
 
-    crate fn maybe_recover_unexpected_block_label(&mut self) -> bool {
+    pub(crate) fn maybe_recover_unexpected_block_label(&mut self) -> bool {
         let Some(label) = self.eat_label().filter(|_| {
             self.eat(&token::Colon) && self.token.kind == token::OpenDelim(Delimiter::Brace)
         }) else {
@@ -2565,7 +2629,7 @@
         err.tool_only_span_suggestion(
             label.ident.span.until(self.token.span),
             "remove this block label",
-            String::new(),
+            "",
             Applicability::MachineApplicable,
         );
         err.emit();
@@ -2574,13 +2638,12 @@
 
     /// Some special error handling for the "top-level" patterns in a match arm,
     /// `for` loop, `let`, &c. (in contrast to subpatterns within such).
-    crate fn maybe_recover_unexpected_comma(
+    pub(crate) fn maybe_recover_unexpected_comma(
         &mut self,
         lo: Span,
-        rc: RecoverComma,
         rt: CommaRecoveryMode,
     ) -> PResult<'a, ()> {
-        if rc == RecoverComma::No || self.token != token::Comma {
+        if self.token != token::Comma {
             return Ok(());
         }
 
@@ -2621,7 +2684,7 @@
         Err(err)
     }
 
-    crate fn maybe_recover_bounds_doubled_colon(&mut self, ty: &Ty) -> PResult<'a, ()> {
+    pub(crate) fn maybe_recover_bounds_doubled_colon(&mut self, ty: &Ty) -> PResult<'a, ()> {
         let TyKind::Path(qself, path) = &ty.kind else { return Ok(()) };
         let qself_position = qself.as_ref().map(|qself| qself.position);
         for (i, segments) in path.segments.windows(2).enumerate() {
@@ -2639,7 +2702,7 @@
                     err.span_suggestion(
                         between_span,
                         "use single colon",
-                        ": ".to_owned(),
+                        ": ",
                         Applicability::MachineApplicable,
                     );
                     return Err(err);
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 6114e7a..81bab0e 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -13,10 +13,13 @@
 use rustc_ast::util::classify;
 use rustc_ast::util::literal::LitError;
 use rustc_ast::util::parser::{prec_let_scrutinee_needs_par, AssocOp, Fixity};
+use rustc_ast::visit::Visitor;
+use rustc_ast::StmtKind;
 use rustc_ast::{self as ast, AttrStyle, AttrVec, CaptureBy, ExprField, Lit, UnOp, DUMMY_NODE_ID};
 use rustc_ast::{AnonConst, BinOp, BinOpKind, FnDecl, FnRetTy, MacCall, Param, Ty, TyKind};
 use rustc_ast::{Arm, Async, BlockCheckMode, Expr, ExprKind, Label, Movability, RangeLimits};
 use rustc_ast_pretty::pprust;
+use rustc_data_structures::thin_vec::ThinVec;
 use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, PResult};
 use rustc_session::lint::builtin::BREAK_WITH_LABEL_AND_LOOP;
 use rustc_session::lint::BuiltinLintDiagnostics;
@@ -227,7 +230,7 @@
                     .span_suggestion_short(
                         sp,
                         &format!("`{s}=` is not a valid comparison operator, use `{s}`", s = sugg),
-                        sugg.to_string(),
+                        sugg,
                         Applicability::MachineApplicable,
                     )
                     .emit();
@@ -244,7 +247,7 @@
                     .span_suggestion_short(
                         sp,
                         "`<>` is not a valid comparison operator, use `!=`",
-                        "!=".to_string(),
+                        "!=",
                         Applicability::MachineApplicable,
                     )
                     .emit();
@@ -456,7 +459,7 @@
             .span_suggestion_short(
                 self.token.span,
                 &format!("use `{good}` to perform logical {english}"),
-                good.to_string(),
+                good,
                 Applicability::MachineApplicable,
             )
             .note("unlike in e.g., python and PHP, `&&` and `||` are used for logical operators")
@@ -581,7 +584,7 @@
                     err.span_suggestion_verbose(
                         lo,
                         "try removing the `+`",
-                        "".to_string(),
+                        "",
                         Applicability::MachineApplicable,
                     );
                 }
@@ -631,7 +634,7 @@
             .span_suggestion_short(
                 lo,
                 "use `!` to perform bitwise not",
-                "!".to_owned(),
+                "!",
                 Applicability::MachineApplicable,
             )
             .emit();
@@ -670,7 +673,7 @@
             // trailing whitespace after the `!` in our suggestion
             self.sess.source_map().span_until_non_whitespace(lo.to(not_token.span)),
             "use `!` to perform logical negation",
-            "!".to_owned(),
+            "!",
             Applicability::MachineApplicable,
         )
         .emit();
@@ -741,7 +744,7 @@
                                     .span_suggestion(
                                         label.ident.span,
                                         "use the correct loop label format",
-                                        label.ident.to_string(),
+                                        label.ident,
                                         Applicability::MachineApplicable,
                                     )
                                     .emit();
@@ -882,7 +885,7 @@
                         "{}remove the type ascription",
                         if is_nightly { "alternatively, " } else { "" }
                     ),
-                    String::new(),
+                    "",
                     if is_nightly {
                         Applicability::MaybeIncorrect
                     } else {
@@ -926,7 +929,7 @@
             .span_suggestion(
                 lt_span,
                 "remove the lifetime annotation",
-                String::new(),
+                "",
                 Applicability::MachineApplicable,
             )
             .emit();
@@ -977,12 +980,26 @@
 
     fn parse_dot_or_call_expr_with_(&mut self, mut e: P<Expr>, lo: Span) -> PResult<'a, P<Expr>> {
         loop {
-            if self.eat(&token::Question) {
+            let has_question = if self.prev_token.kind == TokenKind::Ident(kw::Return, false) {
+                // we are using noexpect here because we don't expect a `?` directly after a `return`
+                // which could be suggested otherwise
+                self.eat_noexpect(&token::Question)
+            } else {
+                self.eat(&token::Question)
+            };
+            if has_question {
                 // `expr?`
                 e = self.mk_expr(lo.to(self.prev_token.span), ExprKind::Try(e), AttrVec::new());
                 continue;
             }
-            if self.eat(&token::Dot) {
+            let has_dot = if self.prev_token.kind == TokenKind::Ident(kw::Return, false) {
+                // we are using noexpect here because we don't expect a `.` directly after a `return`
+                // which could be suggested otherwise
+                self.eat_noexpect(&token::Dot)
+            } else {
+                self.eat(&token::Dot)
+            };
+            if has_dot {
                 // expr.f
                 e = self.parse_dot_suffix_expr(lo, e)?;
                 continue;
@@ -1417,7 +1434,7 @@
         match self.parse_opt_lit() {
             Some(literal) => {
                 let expr = self.mk_expr(lo.to(self.prev_token.span), ExprKind::Lit(literal), attrs);
-                self.maybe_recover_from_bad_qpath(expr, true)
+                self.maybe_recover_from_bad_qpath(expr)
             }
             None => self.try_macro_suggestion(),
         }
@@ -1444,7 +1461,7 @@
             ExprKind::Tup(es)
         };
         let expr = self.mk_expr(lo.to(self.prev_token.span), kind, attrs);
-        self.maybe_recover_from_bad_qpath(expr, true)
+        self.maybe_recover_from_bad_qpath(expr)
     }
 
     fn parse_array_or_repeat_expr(
@@ -1481,7 +1498,7 @@
             }
         };
         let expr = self.mk_expr(lo.to(self.prev_token.span), kind, attrs);
-        self.maybe_recover_from_bad_qpath(expr, true)
+        self.maybe_recover_from_bad_qpath(expr)
     }
 
     fn parse_path_start_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
@@ -1519,7 +1536,7 @@
         };
 
         let expr = self.mk_expr(lo.to(hi), kind, attrs);
-        self.maybe_recover_from_bad_qpath(expr, true)
+        self.maybe_recover_from_bad_qpath(expr)
     }
 
     /// Parse `'label: $expr`. The label is already parsed.
@@ -1538,9 +1555,13 @@
             self.parse_for_expr(label, lo, attrs)
         } else if self.eat_keyword(kw::Loop) {
             self.parse_loop_expr(label, lo, attrs)
-        } else if self.check(&token::OpenDelim(Delimiter::Brace)) || self.token.is_whole_block() {
+        } else if self.check_noexpect(&token::OpenDelim(Delimiter::Brace))
+            || self.token.is_whole_block()
+        {
             self.parse_block_expr(label, lo, BlockCheckMode::Default, attrs)
-        } else if !ate_colon && (self.check(&TokenKind::Comma) || self.check(&TokenKind::Gt)) {
+        } else if !ate_colon
+            && (self.check_noexpect(&TokenKind::Comma) || self.check_noexpect(&TokenKind::Gt))
+        {
             // We're probably inside of a `Path<'a>` that needs a turbofish
             let msg = "expected `while`, `for`, `loop` or `{` after a label";
             self.struct_span_err(self.token.span, msg).span_label(self.token.span, msg).emit();
@@ -1548,9 +1569,66 @@
             Ok(self.mk_expr_err(lo))
         } else {
             let msg = "expected `while`, `for`, `loop` or `{` after a label";
-            self.struct_span_err(self.token.span, msg).span_label(self.token.span, msg).emit();
+
+            let mut err = self.struct_span_err(self.token.span, msg);
+            err.span_label(self.token.span, msg);
+
             // Continue as an expression in an effort to recover on `'label: non_block_expr`.
-            self.parse_expr()
+            let expr = self.parse_expr().map(|expr| {
+                let span = expr.span;
+
+                let found_labeled_breaks = {
+                    struct FindLabeledBreaksVisitor(bool);
+
+                    impl<'ast> Visitor<'ast> for FindLabeledBreaksVisitor {
+                        fn visit_expr_post(&mut self, ex: &'ast Expr) {
+                            if let ExprKind::Break(Some(_label), _) = ex.kind {
+                                self.0 = true;
+                            }
+                        }
+                    }
+
+                    let mut vis = FindLabeledBreaksVisitor(false);
+                    vis.visit_expr(&expr);
+                    vis.0
+                };
+
+                // Suggestion involves adding a (as of time of writing this, unstable) labeled block.
+                //
+                // If there are no breaks that may use this label, suggest removing the label and
+                // recover to the unmodified expression.
+                if !found_labeled_breaks {
+                    let msg = "consider removing the label";
+                    err.span_suggestion_verbose(
+                        lo.until(span),
+                        msg,
+                        "",
+                        Applicability::MachineApplicable,
+                    );
+
+                    return expr;
+                }
+
+                let sugg_msg = "consider enclosing expression in a block";
+                let suggestions = vec![
+                    (span.shrink_to_lo(), "{ ".to_owned()),
+                    (span.shrink_to_hi(), " }".to_owned()),
+                ];
+
+                err.multipart_suggestion_verbose(
+                    sugg_msg,
+                    suggestions,
+                    Applicability::MachineApplicable,
+                );
+
+                // Replace `'label: non_block_expr` with `'label: {non_block_expr}` in order to supress future errors about `break 'label`.
+                let stmt = self.mk_stmt(span, StmtKind::Expr(expr));
+                let blk = self.mk_block(vec![stmt], BlockCheckMode::Default, span);
+                self.mk_expr(span, ExprKind::Block(blk, label), ThinVec::new())
+            });
+
+            err.emit();
+            expr
         }?;
 
         if !ate_colon && consume_colon {
@@ -1566,7 +1644,7 @@
             .span_suggestion_short(
                 lo.shrink_to_hi(),
                 "add `:` after the label",
-                ": ".to_string(),
+                ": ",
                 Applicability::MachineApplicable,
             )
             .note("labels are used before loops and blocks, allowing e.g., `break 'label` to them")
@@ -1585,7 +1663,7 @@
             .span_suggestion(
                 span_dc,
                 "replace with the new syntax",
-                "try".to_string(),
+                "try",
                 Applicability::MachineApplicable,
             )
             .note("following RFC #2388, the new non-placeholder syntax is `try`")
@@ -1604,7 +1682,7 @@
         let lo = self.prev_token.span;
         let kind = ExprKind::Ret(self.parse_expr_opt()?);
         let expr = self.mk_expr(lo.to(self.prev_token.span), kind, attrs);
-        self.maybe_recover_from_bad_qpath(expr, true)
+        self.maybe_recover_from_bad_qpath(expr)
     }
 
     /// Parse `"do" "yeet" expr?`.
@@ -1619,7 +1697,7 @@
         let span = lo.to(self.prev_token.span);
         self.sess.gated_spans.gate(sym::yeet_expr, span);
         let expr = self.mk_expr(span, kind, attrs);
-        self.maybe_recover_from_bad_qpath(expr, true)
+        self.maybe_recover_from_bad_qpath(expr)
     }
 
     /// Parse `"break" (('label (:? expr)?) | expr?)` with `"break"` token already eaten.
@@ -1679,7 +1757,7 @@
             None
         };
         let expr = self.mk_expr(lo.to(self.prev_token.span), ExprKind::Break(label, kind), attrs);
-        self.maybe_recover_from_bad_qpath(expr, true)
+        self.maybe_recover_from_bad_qpath(expr)
     }
 
     /// Parse `"yield" expr?`.
@@ -1689,7 +1767,7 @@
         let span = lo.to(self.prev_token.span);
         self.sess.gated_spans.gate(sym::generators, span);
         let expr = self.mk_expr(span, kind, attrs);
-        self.maybe_recover_from_bad_qpath(expr, true)
+        self.maybe_recover_from_bad_qpath(expr)
     }
 
     /// Returns a string literal if the next token is a string literal.
@@ -2010,6 +2088,12 @@
         Ok(self.mk_expr(blk.span, ExprKind::Block(blk, opt_label), attrs))
     }
 
+    /// Parse a block which takes no attributes and has no label
+    fn parse_simple_block(&mut self) -> PResult<'a, P<Expr>> {
+        let blk = self.parse_block()?;
+        Ok(self.mk_expr(blk.span, ExprKind::Block(blk, None), AttrVec::new()))
+    }
+
     /// Recover on an explicitly quantified closure expression, e.g., `for<'a> |x: &'a u8| *x + 1`.
     fn recover_quantified_closure_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
         let lo = self.token.span;
@@ -2022,7 +2106,7 @@
             .span_suggestion(
                 span_for,
                 "remove the parameters",
-                String::new(),
+                "",
                 Applicability::MachineApplicable,
             )
             .emit();
@@ -2157,35 +2241,66 @@
         let lo = self.prev_token.span;
         let cond = self.parse_cond_expr()?;
 
-        let missing_then_block_binop_span = || {
-            match cond.kind {
-                ExprKind::Binary(Spanned { span: binop_span, .. }, _, ref right)
-                    if let ExprKind::Block(..) = right.kind => Some(binop_span),
-                _ => None
+        self.parse_if_after_cond(attrs, lo, cond)
+    }
+
+    fn parse_if_after_cond(
+        &mut self,
+        attrs: AttrVec,
+        lo: Span,
+        mut cond: P<Expr>,
+    ) -> PResult<'a, P<Expr>> {
+        let cond_span = cond.span;
+        // Tries to interpret `cond` as either a missing expression if it's a block,
+        // or as an unfinished expression if it's a binop and the RHS is a block.
+        // We could probably add more recoveries here too...
+        let mut recover_block_from_condition = |this: &mut Self| {
+            let block = match &mut cond.kind {
+                ExprKind::Binary(Spanned { span: binop_span, .. }, _, right)
+                    if let ExprKind::Block(_, None) = right.kind => {
+                        this.error_missing_if_then_block(lo, cond_span.shrink_to_lo().to(*binop_span), true).emit();
+                        std::mem::replace(right, this.mk_expr_err(binop_span.shrink_to_hi()))
+                    },
+                ExprKind::Block(_, None) => {
+                    this.error_missing_if_cond(lo, cond_span).emit();
+                    std::mem::replace(&mut cond, this.mk_expr_err(cond_span.shrink_to_hi()))
+                }
+                _ => {
+                    return None;
+                }
+            };
+            if let ExprKind::Block(block, _) = &block.kind {
+                Some(block.clone())
+            } else {
+                unreachable!()
             }
         };
-
-        // Verify that the parsed `if` condition makes sense as a condition. If it is a block, then
-        // verify that the last statement is either an implicit return (no `;`) or an explicit
-        // return. This won't catch blocks with an explicit `return`, but that would be caught by
-        // the dead code lint.
-        let thn = if self.token.is_keyword(kw::Else) || !cond.returns() {
-            if let Some(binop_span) = missing_then_block_binop_span() {
-                self.error_missing_if_then_block(lo, None, Some(binop_span)).emit();
-                self.mk_block_err(cond.span)
+        // Parse then block
+        let thn = if self.token.is_keyword(kw::Else) {
+            if let Some(block) = recover_block_from_condition(self) {
+                block
             } else {
-                self.error_missing_if_cond(lo, cond.span)
+                self.error_missing_if_then_block(lo, cond_span, false).emit();
+                self.mk_block_err(cond_span.shrink_to_hi())
             }
         } else {
             let attrs = self.parse_outer_attributes()?.take_for_recovery(); // For recovery.
-            let not_block = self.token != token::OpenDelim(Delimiter::Brace);
-            let block = self.parse_block().map_err(|err| {
-                if not_block {
-                    self.error_missing_if_then_block(lo, Some(err), missing_then_block_binop_span())
+            let block = if self.check(&token::OpenDelim(Delimiter::Brace)) {
+                self.parse_block()?
+            } else {
+                if let Some(block) = recover_block_from_condition(self) {
+                    block
                 } else {
-                    err
+                    // Parse block, which will always fail, but we can add a nice note to the error
+                    self.parse_block().map_err(|mut err| {
+                        err.span_note(
+                            cond_span,
+                            "the `if` expression is missing a block after this condition",
+                        );
+                        err
+                    })?
                 }
-            })?;
+            };
             self.error_on_if_block_attrs(lo, false, block.span, &attrs);
             block
         };
@@ -2196,31 +2311,34 @@
     fn error_missing_if_then_block(
         &self,
         if_span: Span,
-        err: Option<DiagnosticBuilder<'a, ErrorGuaranteed>>,
-        binop_span: Option<Span>,
+        cond_span: Span,
+        is_unfinished: bool,
     ) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
-        let msg = "this `if` expression has a condition, but no block";
-
-        let mut err = if let Some(mut err) = err {
-            err.span_label(if_span, msg);
-            err
+        let mut err = self.struct_span_err(
+            if_span,
+            "this `if` expression is missing a block after the condition",
+        );
+        if is_unfinished {
+            err.span_help(cond_span, "this binary operation is possibly unfinished");
         } else {
-            self.struct_span_err(if_span, msg)
-        };
-
-        if let Some(binop_span) = binop_span {
-            err.span_help(binop_span, "maybe you forgot the right operand of the condition?");
+            err.span_help(cond_span.shrink_to_hi(), "add a block here");
         }
-
         err
     }
 
-    fn error_missing_if_cond(&self, lo: Span, span: Span) -> P<ast::Block> {
-        let sp = self.sess.source_map().next_point(lo);
-        self.struct_span_err(sp, "missing condition for `if` expression")
-            .span_label(sp, "expected if condition here")
-            .emit();
-        self.mk_block_err(span)
+    fn error_missing_if_cond(
+        &self,
+        lo: Span,
+        span: Span,
+    ) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
+        let next_span = self.sess.source_map().next_point(lo);
+        let mut err = self.struct_span_err(next_span, "missing condition for `if` expression");
+        err.span_label(next_span, "expected condition here");
+        err.span_label(
+            self.sess.source_map().start_point(span),
+            "if this block is the condition of the `if` expression, then it must be followed by another block"
+        );
+        err
     }
 
     /// Parses the condition of a `if` or `while` expression.
@@ -2256,15 +2374,46 @@
 
     /// Parses an `else { ... }` expression (`else` token already eaten).
     fn parse_else_expr(&mut self) -> PResult<'a, P<Expr>> {
-        let ctx_span = self.prev_token.span; // `else`
+        let else_span = self.prev_token.span; // `else`
         let attrs = self.parse_outer_attributes()?.take_for_recovery(); // For recovery.
         let expr = if self.eat_keyword(kw::If) {
             self.parse_if_expr(AttrVec::new())?
+        } else if self.check(&TokenKind::OpenDelim(Delimiter::Brace)) {
+            self.parse_simple_block()?
         } else {
-            let blk = self.parse_block()?;
-            self.mk_expr(blk.span, ExprKind::Block(blk, None), AttrVec::new())
+            let snapshot = self.create_snapshot_for_diagnostic();
+            let first_tok = super::token_descr(&self.token);
+            let first_tok_span = self.token.span;
+            match self.parse_expr() {
+                Ok(cond)
+                // If it's not a free-standing expression, and is followed by a block,
+                // then it's very likely the condition to an `else if`.
+                    if self.check(&TokenKind::OpenDelim(Delimiter::Brace))
+                        && classify::expr_requires_semi_to_be_stmt(&cond) =>
+                {
+                    self.struct_span_err(first_tok_span, format!("expected `{{`, found {first_tok}"))
+                        .span_label(else_span, "expected an `if` or a block after this `else`")
+                        .span_suggestion(
+                            cond.span.shrink_to_lo(),
+                            "add an `if` if this is the condition of a chained `else if` statement",
+                            "if ",
+                            Applicability::MaybeIncorrect,
+                        )
+                        .emit();
+                    self.parse_if_after_cond(AttrVec::new(), cond.span.shrink_to_lo(), cond)?
+                }
+                Err(e) => {
+                    e.cancel();
+                    self.restore_snapshot(snapshot);
+                    self.parse_simple_block()?
+                },
+                Ok(_) => {
+                    self.restore_snapshot(snapshot);
+                    self.parse_simple_block()?
+                },
+            }
         };
-        self.error_on_if_block_attrs(ctx_span, true, expr.span, &attrs);
+        self.error_on_if_block_attrs(else_span, true, expr.span, &attrs);
         Ok(expr)
     }
 
@@ -2283,12 +2432,7 @@
         self.struct_span_err(last, "outer attributes are not allowed on `if` and `else` branches")
             .span_label(branch_span, "the attributes are attached to this branch")
             .span_label(ctx_span, format!("the branch belongs to this `{ctx}`"))
-            .span_suggestion(
-                span,
-                "remove the attributes",
-                String::new(),
-                Applicability::MachineApplicable,
-            )
+            .span_suggestion(span, "remove the attributes", "", Applicability::MachineApplicable)
             .emit();
     }
 
@@ -2380,7 +2524,7 @@
         Ok(self.mk_expr(lo.to(self.prev_token.span), ExprKind::Loop(body, opt_label), attrs))
     }
 
-    crate fn eat_label(&mut self) -> Option<Label> {
+    pub(crate) fn eat_label(&mut self) -> Option<Label> {
         self.token.lifetime().map(|ident| {
             self.bump();
             Label { ident }
@@ -2397,7 +2541,7 @@
                 e.span_suggestion_short(
                     match_span,
                     "try removing this `match`",
-                    String::new(),
+                    "",
                     Applicability::MaybeIncorrect, // speculative
                 );
             }
@@ -2473,7 +2617,7 @@
                 err.span_suggestion(
                     semi_sp,
                     "use a comma to end a `match` arm expression",
-                    ",".to_string(),
+                    ",",
                     Applicability::MachineApplicable,
                 );
             }
@@ -2574,7 +2718,7 @@
                     err.span_suggestion(
                         this.token.span,
                         "try using a fat arrow here",
-                        "=>".to_string(),
+                        "=>",
                         Applicability::MaybeIncorrect,
                     );
                     err.emit();
@@ -2613,13 +2757,12 @@
                     ));
                 }
                 this.expect_one_of(&[token::Comma], &[token::CloseDelim(Delimiter::Brace)])
-                    .map_err(|mut err| {
-                        match (sm.span_to_lines(expr.span), sm.span_to_lines(arm_start_span)) {
-                            (Ok(ref expr_lines), Ok(ref arm_start_lines))
-                                if arm_start_lines.lines[0].end_col
-                                    == expr_lines.lines[0].end_col
-                                    && expr_lines.lines.len() == 2
-                                    && this.token == token::FatArrow =>
+                    .or_else(|mut err| {
+                        if this.token == token::FatArrow {
+                            if let Ok(expr_lines) = sm.span_to_lines(expr.span)
+                            && let Ok(arm_start_lines) = sm.span_to_lines(arm_start_span)
+                            && arm_start_lines.lines[0].end_col == expr_lines.lines[0].end_col
+                            && expr_lines.lines.len() == 2
                             {
                                 // We check whether there's any trailing code in the parse span,
                                 // if there isn't, we very likely have the following:
@@ -2635,18 +2778,44 @@
                                 err.span_suggestion_short(
                                     arm_start_span.shrink_to_hi(),
                                     "missing a comma here to end this `match` arm",
-                                    ",".to_owned(),
+                                    ",",
                                     Applicability::MachineApplicable,
                                 );
+                                return Err(err);
                             }
-                            _ => {
-                                err.span_label(
-                                    arrow_span,
-                                    "while parsing the `match` arm starting here",
-                                );
+                        } else {
+                            // FIXME(compiler-errors): We could also recover `; PAT =>` here
+
+                            // Try to parse a following `PAT =>`, if successful
+                            // then we should recover.
+                            let mut snapshot = this.create_snapshot_for_diagnostic();
+                            let pattern_follows = snapshot
+                                .parse_pat_allow_top_alt(
+                                    None,
+                                    RecoverComma::Yes,
+                                    RecoverColon::Yes,
+                                    CommaRecoveryMode::EitherTupleOrPipe,
+                                )
+                                .map_err(|err| err.cancel())
+                                .is_ok();
+                            if pattern_follows && snapshot.check(&TokenKind::FatArrow) {
+                                err.cancel();
+                                this.struct_span_err(
+                                    hi.shrink_to_hi(),
+                                    "expected `,` following `match` arm",
+                                )
+                                .span_suggestion(
+                                    hi.shrink_to_hi(),
+                                    "missing a comma here to end this `match` arm",
+                                    ",",
+                                    Applicability::MachineApplicable,
+                                )
+                                .emit();
+                                return Ok(true);
                             }
                         }
-                        err
+                        err.span_label(arrow_span, "while parsing the `match` arm starting here");
+                        Err(err)
                     })?;
             } else {
                 this.eat(&token::Comma);
@@ -2919,7 +3088,7 @@
         .span_suggestion_short(
             self.token.span,
             "remove this comma",
-            String::new(),
+            "",
             Applicability::MachineApplicable,
         )
         .note("the base struct must always be the last field")
@@ -2973,7 +3142,7 @@
             .span_suggestion(
                 field_name.span.shrink_to_hi().to(self.token.span),
                 "replace equals symbol with a colon",
-                ":".to_string(),
+                ":",
                 Applicability::MachineApplicable,
             )
             .emit();
@@ -2984,13 +3153,13 @@
             .span_suggestion(
                 span,
                 "use `..` for an exclusive range",
-                "..".to_owned(),
+                "..",
                 Applicability::MaybeIncorrect,
             )
             .span_suggestion(
                 span,
                 "or `..=` for an inclusive range",
-                "..=".to_owned(),
+                "..=",
                 Applicability::MaybeIncorrect,
             )
             .emit();
@@ -3002,7 +3171,7 @@
                 span,
                 "if you meant to write a comparison against a negative value, add a \
              space in between `<` and `-`",
-                "< -".to_string(),
+                "< -",
                 Applicability::MaybeIncorrect,
             )
             .emit();
@@ -3049,7 +3218,7 @@
         await_expr
     }
 
-    crate fn mk_expr(&self, span: Span, kind: ExprKind, attrs: AttrVec) -> P<Expr> {
+    pub(crate) fn mk_expr(&self, span: Span, kind: ExprKind, attrs: AttrVec) -> P<Expr> {
         P(Expr { kind, span, attrs, id: DUMMY_NODE_ID, tokens: None })
     }
 
diff --git a/compiler/rustc_parse/src/parser/generics.rs b/compiler/rustc_parse/src/parser/generics.rs
index 8081bac..1acfd93 100644
--- a/compiler/rustc_parse/src/parser/generics.rs
+++ b/compiler/rustc_parse/src/parser/generics.rs
@@ -51,7 +51,7 @@
         })
     }
 
-    crate fn parse_const_param(
+    pub(crate) fn parse_const_param(
         &mut self,
         preceding_attrs: Vec<Attribute>,
     ) -> PResult<'a, GenericParam> {
@@ -271,7 +271,7 @@
                 err.span_suggestion_verbose(
                     prev_token.shrink_to_hi().to(self.prev_token.span),
                     "consider joining the two `where` clauses into one",
-                    ",".to_owned(),
+                    ",",
                     Applicability::MaybeIncorrect,
                 );
                 err.emit();
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index 0f940cf..bf685aa 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -204,25 +204,7 @@
         let mut def = || mem::replace(def, Defaultness::Final);
 
         let info = if self.eat_keyword(kw::Use) {
-            // USE ITEM
-            let tree = self.parse_use_tree()?;
-
-            // If wildcard or glob-like brace syntax doesn't have `;`,
-            // the user may not know `*` or `{}` should be the last.
-            if let Err(mut e) = self.expect_semi() {
-                match tree.kind {
-                    UseTreeKind::Glob => {
-                        e.note("the wildcard token must be last on the path");
-                    }
-                    UseTreeKind::Nested(..) => {
-                        e.note("glob-like brace syntax must be last on the path");
-                    }
-                    _ => (),
-                }
-                return Err(e);
-            }
-
-            (Ident::empty(), ItemKind::Use(tree))
+            self.parse_use_item()?
         } else if self.check_fn_front_matter(def_final) {
             // FUNCTION ITEM
             let (ident, sig, generics, body) = self.parse_fn(attrs, fn_parse_mode, lo, vis)?;
@@ -288,7 +270,12 @@
         } else if let IsMacroRulesItem::Yes { has_bang } = self.is_macro_rules_item() {
             // MACRO_RULES ITEM
             self.parse_item_macro_rules(vis, has_bang)?
-        } else if vis.kind.is_pub() && self.isnt_macro_invocation() {
+        } else if self.isnt_macro_invocation()
+            && (self.token.is_ident_named(Symbol::intern("import"))
+                || self.token.is_ident_named(Symbol::intern("using")))
+        {
+            return self.recover_import_as_use();
+        } else if self.isnt_macro_invocation() && vis.kind.is_pub() {
             self.recover_missing_kw_before_item()?;
             return Ok(None);
         } else if macros_allowed && self.check_path() {
@@ -300,10 +287,51 @@
         Ok(Some(info))
     }
 
+    fn recover_import_as_use(&mut self) -> PResult<'a, Option<(Ident, ItemKind)>> {
+        let span = self.token.span;
+        let token_name = super::token_descr(&self.token);
+        let snapshot = self.create_snapshot_for_diagnostic();
+        self.bump();
+        match self.parse_use_item() {
+            Ok(u) => {
+                self.struct_span_err(span, format!("expected item, found {token_name}"))
+                    .span_suggestion_short(
+                        span,
+                        "items are imported using the `use` keyword",
+                        "use",
+                        Applicability::MachineApplicable,
+                    )
+                    .emit();
+                Ok(Some(u))
+            }
+            Err(e) => {
+                e.cancel();
+                self.restore_snapshot(snapshot);
+                Ok(None)
+            }
+        }
+    }
+
+    fn parse_use_item(&mut self) -> PResult<'a, (Ident, ItemKind)> {
+        let tree = self.parse_use_tree()?;
+        if let Err(mut e) = self.expect_semi() {
+            match tree.kind {
+                UseTreeKind::Glob => {
+                    e.note("the wildcard token must be last on the path");
+                }
+                UseTreeKind::Nested(..) => {
+                    e.note("glob-like brace syntax must be last on the path");
+                }
+                _ => (),
+            }
+            return Err(e);
+        }
+        Ok((Ident::empty(), ItemKind::Use(tree)))
+    }
+
     /// When parsing a statement, would the start of a path be an item?
     pub(super) fn is_path_start_item(&mut self) -> bool {
-        self.is_crate_vis() // no: `crate::b`, yes: `crate $item`
-        || self.is_kw_followed_by_ident(kw::Union) // no: `union::b`, yes: `union U { .. }`
+        self.is_kw_followed_by_ident(kw::Union) // no: `union::b`, yes: `union U { .. }`
         || self.check_auto_or_unsafe_trait_item() // no: `auto::b`, yes: `auto trait X { .. }`
         || self.is_async_fn() // no(2015): `async::b`, yes: `async fn`
         || matches!(self.is_macro_rules_item(), IsMacroRulesItem::Yes{..}) // no: `macro_rules::b`, yes: `macro_rules! mac`
@@ -430,7 +458,7 @@
                     err.span_suggestion(
                         path.span,
                         "perhaps you meant to define a macro",
-                        "macro_rules".to_string(),
+                        "macro_rules",
                         Applicability::MachineApplicable,
                     );
                 }
@@ -458,7 +486,7 @@
                 err.span_suggestion_verbose(
                     self.token.span,
                     "consider removing this semicolon",
-                    String::new(),
+                    "",
                     Applicability::MaybeIncorrect,
                 );
             }
@@ -578,7 +606,7 @@
                         .span_suggestion_short(
                             missing_for_span,
                             "add `for` here",
-                            " for ".to_string(),
+                            " for ",
                             Applicability::MachineApplicable,
                         )
                         .emit();
@@ -997,35 +1025,24 @@
     fn parse_item_foreign_mod(
         &mut self,
         attrs: &mut Vec<Attribute>,
-        unsafety: Unsafe,
+        mut unsafety: Unsafe,
     ) -> PResult<'a, ItemInfo> {
-        let sp_start = self.prev_token.span;
         let abi = self.parse_abi(); // ABI?
-        match self.parse_item_list(attrs, |p| p.parse_foreign_item(ForceCollect::No)) {
-            Ok(items) => {
-                let module = ast::ForeignMod { unsafety, abi, items };
-                Ok((Ident::empty(), ItemKind::ForeignMod(module)))
-            }
-            Err(mut err) => {
-                let current_qual_sp = self.prev_token.span;
-                let current_qual_sp = current_qual_sp.to(sp_start);
-                if let Ok(current_qual) = self.span_to_snippet(current_qual_sp) {
-                    // FIXME(davidtwco): avoid depending on the error message text
-                    if err.message[0].0.expect_str() == "expected `{`, found keyword `unsafe`" {
-                        let invalid_qual_sp = self.token.uninterpolated_span();
-                        let invalid_qual = self.span_to_snippet(invalid_qual_sp).unwrap();
-
-                        err.span_suggestion(
-                                current_qual_sp.to(invalid_qual_sp),
-                                &format!("`{}` must come before `{}`", invalid_qual, current_qual),
-                                format!("{} {}", invalid_qual, current_qual),
-                                Applicability::MachineApplicable,
-                            ).note("keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern`");
-                    }
-                }
-                Err(err)
-            }
+        if unsafety == Unsafe::No
+            && self.token.is_keyword(kw::Unsafe)
+            && self.look_ahead(1, |t| t.kind == token::OpenDelim(Delimiter::Brace))
+        {
+            let mut err = self.expect(&token::OpenDelim(Delimiter::Brace)).unwrap_err();
+            err.emit();
+            unsafety = Unsafe::Yes(self.token.span);
+            self.eat_keyword(kw::Unsafe);
         }
+        let module = ast::ForeignMod {
+            unsafety,
+            abi,
+            items: self.parse_item_list(attrs, |p| p.parse_foreign_item(ForceCollect::No))?,
+        };
+        Ok((Ident::empty(), ItemKind::ForeignMod(module)))
     }
 
     /// Parses a foreign item (one in an `extern { ... }` block).
@@ -1065,7 +1082,7 @@
             .span_suggestion(
                 span.with_hi(ident.span.lo()),
                 "try using a static value",
-                "static ".to_string(),
+                "static ",
                 Applicability::MachineApplicable,
             )
             .note("for more information, visit https://doc.rust-lang.org/std/keyword.extern.html")
@@ -1104,7 +1121,7 @@
                 .span_suggestion(
                     const_span,
                     "you might want to declare a static instead",
-                    "static".to_owned(),
+                    "static",
                     Applicability::MaybeIncorrect,
                 )
                 .emit();
@@ -1538,7 +1555,7 @@
                 err.span_suggestion_short(
                     self.prev_token.span,
                     "field names and their types are separated with `:`",
-                    ":".to_string(),
+                    ":",
                     Applicability::MachineApplicable,
                 );
                 err.emit();
@@ -1565,7 +1582,7 @@
                 .span_suggestion_verbose(
                     self.token.span,
                     "write a path separator here",
-                    "::".to_string(),
+                    "::",
                     Applicability::MaybeIncorrect,
                 )
                 .emit();
@@ -1578,7 +1595,7 @@
                 .span_suggestion(
                     sp,
                     "remove this unsupported default value",
-                    String::new(),
+                    "",
                     Applicability::MachineApplicable,
                 )
                 .emit();
@@ -1674,7 +1691,7 @@
                     .span_suggestion(
                         macro_rules_span,
                         "add a `!`",
-                        "macro_rules!".to_owned(),
+                        "macro_rules!",
                         Applicability::MachineApplicable,
                     )
                     .emit();
@@ -1703,12 +1720,7 @@
             // Handle macro_rules! foo!
             let span = self.prev_token.span;
             self.struct_span_err(span, "macro names aren't followed by a `!`")
-                .span_suggestion(
-                    span,
-                    "remove the `!`",
-                    "".to_owned(),
-                    Applicability::MachineApplicable,
-                )
+                .span_suggestion(span, "remove the `!`", "", Applicability::MachineApplicable)
                 .emit();
         }
 
@@ -1734,7 +1746,7 @@
                 .span_suggestion(
                     vis.span,
                     "try exporting the macro",
-                    "#[macro_export]".to_owned(),
+                    "#[macro_export]",
                     Applicability::MaybeIncorrect, // speculative
                 )
                 .emit();
@@ -1743,7 +1755,7 @@
                 .span_suggestion(
                     vis.span,
                     "remove the visibility",
-                    String::new(),
+                    "",
                     Applicability::MachineApplicable,
                 )
                 .help(&format!("try adjusting the macro to put `{vstr}` inside the invocation"))
@@ -1763,30 +1775,34 @@
             span,
             "macros that expand to items must be delimited with braces or followed by a semicolon",
         );
-        if self.unclosed_delims.is_empty() {
-            let DelimSpan { open, close } = match args {
-                MacArgs::Empty | MacArgs::Eq(..) => unreachable!(),
-                MacArgs::Delimited(dspan, ..) => *dspan,
-            };
-            err.multipart_suggestion(
-                "change the delimiters to curly braces",
-                vec![(open, "{".to_string()), (close, '}'.to_string())],
+        // FIXME: This will make us not emit the help even for declarative
+        // macros within the same crate (that we can fix), which is sad.
+        if !span.from_expansion() {
+            if self.unclosed_delims.is_empty() {
+                let DelimSpan { open, close } = match args {
+                    MacArgs::Empty | MacArgs::Eq(..) => unreachable!(),
+                    MacArgs::Delimited(dspan, ..) => *dspan,
+                };
+                err.multipart_suggestion(
+                    "change the delimiters to curly braces",
+                    vec![(open, "{".to_string()), (close, '}'.to_string())],
+                    Applicability::MaybeIncorrect,
+                );
+            } else {
+                err.span_suggestion(
+                    span,
+                    "change the delimiters to curly braces",
+                    " { /* items */ }",
+                    Applicability::HasPlaceholders,
+                );
+            }
+            err.span_suggestion(
+                span.shrink_to_hi(),
+                "add a semicolon",
+                ';',
                 Applicability::MaybeIncorrect,
             );
-        } else {
-            err.span_suggestion(
-                span,
-                "change the delimiters to curly braces",
-                " { /* items */ }".to_string(),
-                Applicability::HasPlaceholders,
-            );
         }
-        err.span_suggestion(
-            span.shrink_to_hi(),
-            "add a semicolon",
-            ';'.to_string(),
-            Applicability::MaybeIncorrect,
-        );
         err.emit();
     }
 
@@ -1809,7 +1825,7 @@
             .span_suggestion(
                 item.unwrap().span,
                 &format!("consider creating a new `{kw_str}` definition instead of nesting"),
-                String::new(),
+                "",
                 Applicability::MaybeIncorrect,
             )
             .emit();
@@ -2069,7 +2085,7 @@
                         err.span_suggestion(
                             self.token.uninterpolated_span(),
                             &format!("`{original_kw}` already used earlier, remove this one"),
-                            "".to_string(),
+                            "",
                             Applicability::MachineApplicable,
                         )
                         .span_note(original_sp, &format!("`{original_kw}` first seen here"));
@@ -2117,7 +2133,7 @@
                                 err.span_suggestion(
                                     current_vis.span,
                                     "there is already a visibility modifier, remove one",
-                                    "".to_string(),
+                                    "",
                                     Applicability::MachineApplicable,
                                 )
                                 .span_note(orig_vis.span, "explicit visibility first seen here");
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index f32ee9f..6d66677 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -25,7 +25,7 @@
 use rustc_ast::tokenstream::{TokenStream, TokenTree};
 use rustc_ast::AttrId;
 use rustc_ast::DUMMY_NODE_ID;
-use rustc_ast::{self as ast, AnonConst, AttrStyle, AttrVec, Const, CrateSugar, Extern};
+use rustc_ast::{self as ast, AnonConst, AttrStyle, AttrVec, Const, Extern};
 use rustc_ast::{Async, Expr, ExprKind, MacArgs, MacArgsEq, MacDelimiter, Mutability, StrLit};
 use rustc_ast::{HasAttrs, HasTokens, Unsafe, Visibility, VisibilityKind};
 use rustc_ast_pretty::pprust;
@@ -547,6 +547,22 @@
         is_present
     }
 
+    fn check_noexpect(&self, tok: &TokenKind) -> bool {
+        self.token == *tok
+    }
+
+    /// Consumes a token 'tok' if it exists. Returns whether the given token was present.
+    ///
+    /// the main purpose of this function is to reduce the cluttering of the suggestions list
+    /// which using the normal eat method could introduce in some cases.
+    pub fn eat_noexpect(&mut self, tok: &TokenKind) -> bool {
+        let is_present = self.check_noexpect(tok);
+        if is_present {
+            self.bump()
+        }
+        is_present
+    }
+
     /// Consumes a token 'tok' if it exists. Returns whether the given token was present.
     pub fn eat(&mut self, tok: &TokenKind) -> bool {
         let is_present = self.check(tok);
@@ -1245,12 +1261,8 @@
         res
     }
 
-    fn is_crate_vis(&self) -> bool {
-        self.token.is_keyword(kw::Crate) && self.look_ahead(1, |t| t != &token::ModSep)
-    }
-
-    /// Parses `pub`, `pub(crate)` and `pub(in path)` plus shortcuts `crate` for `pub(crate)`,
-    /// `pub(self)` for `pub(in self)` and `pub(super)` for `pub(in super)`.
+    /// Parses `pub` and `pub(in path)` plus shortcuts `pub(crate)` for `pub(in crate)`, `pub(self)`
+    /// for `pub(in self)` and `pub(super)` for `pub(in super)`.
     /// If the following element can't be a tuple (i.e., it's a function definition), then
     /// it's not a tuple struct field), and the contents within the parentheses aren't valid,
     /// so emit a proper diagnostic.
@@ -1258,17 +1270,6 @@
     pub fn parse_visibility(&mut self, fbt: FollowedByType) -> PResult<'a, Visibility> {
         maybe_whole!(self, NtVis, |x| x.into_inner());
 
-        self.expected_tokens.push(TokenType::Keyword(kw::Crate));
-        if self.is_crate_vis() {
-            self.bump(); // `crate`
-            self.sess.gated_spans.gate(sym::crate_visibility_modifier, self.prev_token.span);
-            return Ok(Visibility {
-                span: self.prev_token.span,
-                kind: VisibilityKind::Crate(CrateSugar::JustCrate),
-                tokens: None,
-            });
-        }
-
         if !self.eat_keyword(kw::Pub) {
             // We need a span for our `Spanned<VisibilityKind>`, but there's inherently no
             // keyword to grab a span from for inherited visibility; an empty span at the
@@ -1286,20 +1287,7 @@
             // `()` or a tuple might be allowed. For example, `struct Struct(pub (), pub (usize));`.
             // Because of this, we only `bump` the `(` if we're assured it is appropriate to do so
             // by the following tokens.
-            if self.is_keyword_ahead(1, &[kw::Crate]) && self.look_ahead(2, |t| t != &token::ModSep)
-            // account for `pub(crate::foo)`
-            {
-                // Parse `pub(crate)`.
-                self.bump(); // `(`
-                self.bump(); // `crate`
-                self.expect(&token::CloseDelim(Delimiter::Parenthesis))?; // `)`
-                let vis = VisibilityKind::Crate(CrateSugar::PubCrate);
-                return Ok(Visibility {
-                    span: lo.to(self.prev_token.span),
-                    kind: vis,
-                    tokens: None,
-                });
-            } else if self.is_keyword_ahead(1, &[kw::In]) {
+            if self.is_keyword_ahead(1, &[kw::In]) {
                 // Parse `pub(in path)`.
                 self.bump(); // `(`
                 self.bump(); // `in`
@@ -1312,11 +1300,11 @@
                     tokens: None,
                 });
             } else if self.look_ahead(2, |t| t == &token::CloseDelim(Delimiter::Parenthesis))
-                && self.is_keyword_ahead(1, &[kw::Super, kw::SelfLower])
+                && self.is_keyword_ahead(1, &[kw::Crate, kw::Super, kw::SelfLower])
             {
-                // Parse `pub(self)` or `pub(super)`.
+                // Parse `pub(crate)`, `pub(self)`, or `pub(super)`.
                 self.bump(); // `(`
-                let path = self.parse_path(PathStyle::Mod)?; // `super`/`self`
+                let path = self.parse_path(PathStyle::Mod)?; // `crate`/`super`/`self`
                 self.expect(&token::CloseDelim(Delimiter::Parenthesis))?; // `)`
                 let vis = VisibilityKind::Restricted { path: P(path), id: ast::DUMMY_NODE_ID };
                 return Ok(Visibility {
@@ -1378,7 +1366,7 @@
                         .span_suggestion(
                             lit.span,
                             "specify the ABI with a string literal",
-                            "\"C\"".to_string(),
+                            "\"C\"",
                             Applicability::MaybeIncorrect,
                         )
                         .emit();
@@ -1415,7 +1403,7 @@
     }
 }
 
-crate fn make_unclosed_delims_error(
+pub(crate) fn make_unclosed_delims_error(
     unmatched: UnmatchedBrace,
     sess: &ParseSess,
 ) -> Option<DiagnosticBuilder<'_, ErrorGuaranteed>> {
diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs
index 8019c5f..ba77a39 100644
--- a/compiler/rustc_parse/src/parser/pat.rs
+++ b/compiler/rustc_parse/src/parser/pat.rs
@@ -100,8 +100,10 @@
         };
 
         // Parse the first pattern (`p_0`).
-        let first_pat = self.parse_pat_no_top_alt(expected)?;
-        self.maybe_recover_unexpected_comma(first_pat.span, rc, rt)?;
+        let mut first_pat = self.parse_pat_no_top_alt(expected)?;
+        if rc == RecoverComma::Yes {
+            self.maybe_recover_unexpected_comma(first_pat.span, rt)?;
+        }
 
         // If the next token is not a `|`,
         // this is not an or-pattern and we should exit here.
@@ -111,7 +113,9 @@
             // This complicated procedure is done purely for diagnostics UX.
 
             // Check if the user wrote `foo:bar` instead of `foo::bar`.
-            let first_pat = self.maybe_recover_colon_colon_in_pat_typo(first_pat, ra, expected);
+            if ra == RecoverColon::Yes {
+                first_pat = self.maybe_recover_colon_colon_in_pat_typo(first_pat, expected);
+            }
 
             if let Some(leading_vert_span) = leading_vert_span {
                 // If there was a leading vert, treat this as an or-pattern. This improves
@@ -139,7 +143,9 @@
                 err.span_label(lo, WHILE_PARSING_OR_MSG);
                 err
             })?;
-            self.maybe_recover_unexpected_comma(pat.span, rc, rt)?;
+            if rc == RecoverComma::Yes {
+                self.maybe_recover_unexpected_comma(pat.span, rt)?;
+            }
             pats.push(pat);
         }
         let or_pattern_span = lo.to(self.prev_token.span);
@@ -212,12 +218,7 @@
         if let token::OrOr = self.token.kind {
             let span = self.token.span;
             let mut err = self.struct_span_err(span, "unexpected `||` before function parameter");
-            err.span_suggestion(
-                span,
-                "remove the `||`",
-                String::new(),
-                Applicability::MachineApplicable,
-            );
+            err.span_suggestion(span, "remove the `||`", "", Applicability::MachineApplicable);
             err.note("alternatives in or-patterns are separated with `|`, not `||`");
             err.emit();
             self.bump();
@@ -281,7 +282,7 @@
         err.span_suggestion(
             self.token.span,
             "use a single `|` to separate multiple alternative patterns",
-            "|".to_owned(),
+            "|",
             Applicability::MachineApplicable,
         );
         if let Some(lo) = lo {
@@ -297,7 +298,7 @@
         err.span_suggestion(
             span,
             &format!("remove the `{}`", pprust::token_to_string(&self.token)),
-            String::new(),
+            "",
             Applicability::MachineApplicable,
         );
         if let Some(lo) = lo {
@@ -354,10 +355,7 @@
             let mutbl = self.parse_mutability();
             self.parse_pat_ident(BindingMode::ByRef(mutbl))?
         } else if self.eat_keyword(kw::Box) {
-            // Parse `box pat`
-            let pat = self.parse_pat_with_range_pat(false, None)?;
-            self.sess.gated_spans.gate(sym::box_patterns, lo.to(self.prev_token.span));
-            PatKind::Box(pat)
+            self.parse_pat_box()?
         } else if self.check_inline_const(0) {
             // Parse `const pat`
             let const_expr = self.parse_const_block(lo.to(self.token.span), true)?;
@@ -408,7 +406,7 @@
         };
 
         let pat = self.mk_pat(lo.to(self.prev_token.span), pat);
-        let pat = self.maybe_recover_from_bad_qpath(pat, true)?;
+        let pat = self.maybe_recover_from_bad_qpath(pat)?;
         let pat = self.recover_intersection_pat(pat)?;
 
         if !allow_range_pat {
@@ -430,7 +428,7 @@
             .span_suggestion_short(
                 lo,
                 "for a rest pattern, use `..` instead of `...`",
-                "..".to_owned(),
+                "..",
                 Applicability::MachineApplicable,
             )
             .emit();
@@ -534,12 +532,7 @@
 
             let span = self.prev_token.span;
             self.struct_span_err(span, &format!("unexpected lifetime `{}` in pattern", name))
-                .span_suggestion(
-                    span,
-                    "remove the lifetime",
-                    String::new(),
-                    Applicability::MachineApplicable,
-                )
+                .span_suggestion(span, "remove the lifetime", "", Applicability::MachineApplicable)
                 .emit();
         }
     }
@@ -662,7 +655,7 @@
             .span_suggestion(
                 span,
                 "remove the additional `mut`s",
-                String::new(),
+                "",
                 Applicability::MachineApplicable,
             )
             .emit();
@@ -756,24 +749,14 @@
 
     fn error_inclusive_range_with_extra_equals(&self, span: Span) {
         self.struct_span_err(span, "unexpected `=` after inclusive range")
-            .span_suggestion_short(
-                span,
-                "use `..=` instead",
-                "..=".to_string(),
-                Applicability::MaybeIncorrect,
-            )
+            .span_suggestion_short(span, "use `..=` instead", "..=", Applicability::MaybeIncorrect)
             .note("inclusive ranges end with a single equals sign (`..=`)")
             .emit();
     }
 
     fn error_inclusive_range_with_no_end(&self, span: Span) {
         struct_span_err!(self.sess.span_diagnostic, span, E0586, "inclusive range with no end")
-            .span_suggestion_short(
-                span,
-                "use `..` instead",
-                "..".to_string(),
-                Applicability::MachineApplicable,
-            )
+            .span_suggestion_short(span, "use `..` instead", "..", Applicability::MachineApplicable)
             .note("inclusive ranges must be bounded at the end (`..=b` or `a..=b`)")
             .emit();
     }
@@ -791,7 +774,7 @@
                 .span_suggestion_short(
                     re.span,
                     "use `..=` instead",
-                    "..=".to_string(),
+                    "..=",
                     Applicability::MachineApplicable,
                 )
                 .emit();
@@ -909,6 +892,62 @@
         Ok(PatKind::TupleStruct(qself, path, fields))
     }
 
+    /// Are we sure this could not possibly be the start of a pattern?
+    ///
+    /// Currently, this only accounts for tokens that can follow identifiers
+    /// in patterns, but this can be extended as necessary.
+    fn isnt_pattern_start(&self) -> bool {
+        [
+            token::Eq,
+            token::Colon,
+            token::Comma,
+            token::Semi,
+            token::At,
+            token::OpenDelim(Delimiter::Brace),
+            token::CloseDelim(Delimiter::Brace),
+            token::CloseDelim(Delimiter::Parenthesis),
+        ]
+        .contains(&self.token.kind)
+    }
+
+    /// Parses `box pat`
+    fn parse_pat_box(&mut self) -> PResult<'a, PatKind> {
+        let box_span = self.prev_token.span;
+
+        if self.isnt_pattern_start() {
+            self.struct_span_err(
+                self.token.span,
+                format!("expected pattern, found {}", super::token_descr(&self.token)),
+            )
+            .span_note(box_span, "`box` is a reserved keyword")
+            .span_suggestion_verbose(
+                box_span.shrink_to_lo(),
+                "escape `box` to use it as an identifier",
+                "r#",
+                Applicability::MaybeIncorrect,
+            )
+            .emit();
+
+            // We cannot use `parse_pat_ident()` since it will complain `box`
+            // is not an identifier.
+            let sub = if self.eat(&token::At) {
+                Some(self.parse_pat_no_top_alt(Some("binding pattern"))?)
+            } else {
+                None
+            };
+
+            Ok(PatKind::Ident(
+                BindingMode::ByValue(Mutability::Not),
+                Ident::new(kw::Box, box_span),
+                sub,
+            ))
+        } else {
+            let pat = self.parse_pat_with_range_pat(false, None)?;
+            self.sess.gated_spans.gate(sym::box_patterns, box_span.to(self.prev_token.span));
+            Ok(PatKind::Box(pat))
+        }
+    }
+
     /// Parses the fields of a struct-like pattern.
     fn parse_pat_fields(&mut self) -> PResult<'a, (Vec<PatField>, bool)> {
         let mut fields = Vec::new();
@@ -976,7 +1015,7 @@
                         err.span_suggestion_short(
                             sp,
                             "remove this comma",
-                            String::new(),
+                            "",
                             Applicability::MachineApplicable,
                         );
                     }
@@ -1048,7 +1087,7 @@
             .span_suggestion(
                 self.token.span,
                 "to omit remaining fields, use one fewer `.`",
-                "..".to_owned(),
+                "..",
                 Applicability::MachineApplicable,
             )
             .emit();
diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs
index 5c6fb37..5cf1758 100644
--- a/compiler/rustc_parse/src/parser/path.rs
+++ b/compiler/rustc_parse/src/parser/path.rs
@@ -2,7 +2,7 @@
 use super::{Parser, Restrictions, TokenType};
 use crate::maybe_whole;
 use rustc_ast::ptr::P;
-use rustc_ast::token::{self, Delimiter, Token};
+use rustc_ast::token::{self, Delimiter, Token, TokenKind};
 use rustc_ast::{
     self as ast, AngleBracketedArg, AngleBracketedArgs, AnonConst, AssocConstraint,
     AssocConstraintKind, BlockCheckMode, GenericArg, GenericArgs, Generics, ParenthesizedArgs,
@@ -96,7 +96,7 @@
     ///                ^ help: use double colon
     /// ```
     fn recover_colon_before_qpath_proj(&mut self) -> bool {
-        if self.token.kind != token::Colon
+        if !self.check_noexpect(&TokenKind::Colon)
             || self.look_ahead(1, |t| !t.is_ident() || t.is_reserved_ident())
         {
             return false;
@@ -112,7 +112,7 @@
             .span_suggestion(
                 self.prev_token.span,
                 "use double colon",
-                "::".to_string(),
+                "::",
                 Applicability::MachineApplicable,
             )
             .emit();
@@ -283,7 +283,7 @@
                             err.span_suggestion_verbose(
                                 arg.span().shrink_to_hi(),
                                 "you might have meant to end the type parameters here",
-                                ">".to_string(),
+                                ">",
                                 Applicability::MaybeIncorrect,
                             );
                         }
@@ -455,7 +455,7 @@
                             "remove extra angle bracket{}",
                             pluralize!(snapshot.unmatched_angle_bracket_count)
                         ),
-                        String::new(),
+                        "",
                         Applicability::MachineApplicable,
                     )
                     .emit();
@@ -478,7 +478,7 @@
         while let Some(arg) = self.parse_angle_arg(ty_generics)? {
             args.push(arg);
             if !self.eat(&token::Comma) {
-                if self.token.kind == token::Semi
+                if self.check_noexpect(&TokenKind::Semi)
                     && self.look_ahead(1, |t| t.is_ident() || t.is_lifetime())
                 {
                     // Add `>` to the list of expected tokens.
@@ -489,7 +489,7 @@
                     err.span_suggestion_verbose(
                         self.prev_token.span.until(self.token.span),
                         "use a comma to separate type parameters",
-                        ", ".to_string(),
+                        ", ",
                         Applicability::MachineApplicable,
                     );
                     err.emit();
@@ -517,7 +517,11 @@
         let arg = self.parse_generic_arg(ty_generics)?;
         match arg {
             Some(arg) => {
-                if self.check(&token::Colon) | self.check(&token::Eq) {
+                // we are using noexpect here because we first want to find out if either `=` or `:`
+                // is present and then use that info to push the other token onto the tokens list
+                let separated =
+                    self.check_noexpect(&token::Colon) || self.check_noexpect(&token::Eq);
+                if separated && (self.check(&token::Colon) | self.check(&token::Eq)) {
                     let arg_span = arg.span();
                     let (binder, ident, gen_args) = match self.get_ident_from_generic_arg(&arg) {
                         Ok(ident_gen_args) => ident_gen_args,
@@ -553,6 +557,14 @@
                         AssocConstraint { id: ast::DUMMY_NODE_ID, ident, gen_args, kind, span };
                     Ok(Some(AngleBracketedArg::Constraint(constraint)))
                 } else {
+                    // we only want to suggest `:` and `=` in contexts where the previous token
+                    // is an ident and the current token or the next token is an ident
+                    if self.prev_token.is_ident()
+                        && (self.token.is_ident() || self.look_ahead(1, |token| token.is_ident()))
+                    {
+                        self.check(&token::Colon);
+                        self.check(&token::Eq);
+                    }
                     Ok(Some(AngleBracketedArg::Arg(arg)))
                 }
             }
@@ -592,13 +604,13 @@
                     err.span_suggestion(
                         self.sess.source_map().next_point(eq).to(before_next),
                         "to constrain the associated type, add a type after `=`",
-                        " TheType".to_string(),
+                        " TheType",
                         Applicability::HasPlaceholders,
                     );
                     err.span_suggestion(
                         eq.to(before_next),
                         &format!("remove the `=` if `{}` is a type", ident),
-                        String::new(),
+                        "",
                         Applicability::MaybeIncorrect,
                     )
                 } else {
diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs
index 56ebac0..51bd9d2 100644
--- a/compiler/rustc_parse/src/parser/stmt.rs
+++ b/compiler/rustc_parse/src/parser/stmt.rs
@@ -36,7 +36,7 @@
 
     /// If `force_capture` is true, forces collection of tokens regardless of whether
     /// or not we have attributes
-    crate fn parse_stmt_without_recovery(
+    pub(crate) fn parse_stmt_without_recovery(
         &mut self,
         capture_semi: bool,
         force_collect: ForceCollect,
@@ -180,7 +180,7 @@
         } else {
             // Since none of the above applied, this is an expression statement macro.
             let e = self.mk_expr(lo.to(hi), ExprKind::MacCall(mac), AttrVec::new());
-            let e = self.maybe_recover_from_bad_qpath(e, true)?;
+            let e = self.maybe_recover_from_bad_qpath(e)?;
             let e = self.parse_dot_or_call_expr_with(e, lo, attrs.into())?;
             let e = self.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(e))?;
             StmtKind::Expr(e)
@@ -209,7 +209,7 @@
     ) -> PResult<'a, Stmt> {
         let stmt = self.recover_local_after_let(lo, attrs)?;
         self.struct_span_err(lo, "invalid variable declaration")
-            .span_suggestion(lo, msg, sugg.to_string(), Applicability::MachineApplicable)
+            .span_suggestion(lo, msg, sugg, Applicability::MachineApplicable)
             .emit();
         Ok(stmt)
     }
@@ -260,7 +260,10 @@
                     if let Ok(snip) = self.span_to_snippet(pat.span) {
                         err.span_label(pat.span, format!("while parsing the type for `{}`", snip));
                     }
-                    let err = if self.check(&token::Eq) {
+                    // we use noexpect here because we don't actually expect Eq to be here
+                    // but we are still checking for it in order to be able to handle it if
+                    // it is there
+                    let err = if self.check_noexpect(&token::Eq) {
                         err.emit();
                         None
                     } else {
@@ -287,7 +290,7 @@
                 err.span_suggestion_short(
                     colon_sp,
                     "use `=` if you meant to assign",
-                    " =".to_string(),
+                    " =",
                     Applicability::MachineApplicable,
                 );
                 err.emit();
@@ -391,7 +394,7 @@
                 .span_suggestion_short(
                     self.token.span,
                     "initialize the variable",
-                    "=".to_string(),
+                    "=",
                     Applicability::MaybeIncorrect,
                 )
                 .help("if you meant to overwrite, remove the `let` binding")
@@ -429,10 +432,23 @@
         //
         // which is valid in other languages, but not Rust.
         match self.parse_stmt_without_recovery(false, ForceCollect::No) {
-            // If the next token is an open brace (e.g., `if a b {`), the place-
-            // inside-a-block suggestion would be more likely wrong than right.
+            // If the next token is an open brace, e.g., we have:
+            //
+            //     if expr other_expr {
+            //        ^    ^          ^- lookahead(1) is a brace
+            //        |    |- current token is not "else"
+            //        |- (statement we just parsed)
+            //
+            // the place-inside-a-block suggestion would be more likely wrong than right.
+            //
+            // FIXME(compiler-errors): this should probably parse an arbitrary expr and not
+            // just lookahead one token, so we can see if there's a brace after _that_,
+            // since we want to protect against:
+            //     `if 1 1 + 1 {` being suggested as  `if { 1 } 1 + 1 {`
+            //                                            +   +
             Ok(Some(_))
-                if self.look_ahead(1, |t| t == &token::OpenDelim(Delimiter::Brace))
+                if (!self.token.is_keyword(kw::Else)
+                    && self.look_ahead(1, |t| t == &token::OpenDelim(Delimiter::Brace)))
                     || do_not_suggest_help => {}
             // Do not suggest `if foo println!("") {;}` (as would be seen in test for #46836).
             Ok(Some(Stmt { kind: StmtKind::Empty, .. })) => {}
@@ -500,7 +516,7 @@
 
     /// Parses the rest of a block expression or function body.
     /// Precondition: already parsed the '{'.
-    crate fn parse_block_tail(
+    pub(crate) fn parse_block_tail(
         &mut self,
         lo: Span,
         s: BlockCheckMode,
diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs
index b0439a5..31b40a8 100644
--- a/compiler/rustc_parse/src/parser/ty.rs
+++ b/compiler/rustc_parse/src/parser/ty.rs
@@ -216,7 +216,7 @@
                 .span_suggestion_short(
                     self.prev_token.span,
                     "use `->` instead",
-                    "->".to_string(),
+                    "->",
                     Applicability::MachineApplicable,
                 )
                 .emit();
@@ -312,13 +312,18 @@
         };
 
         let span = lo.to(self.prev_token.span);
-        let ty = self.mk_ty(span, kind);
+        let mut ty = self.mk_ty(span, kind);
 
         // Try to recover from use of `+` with incorrect priority.
-        self.maybe_report_ambiguous_plus(allow_plus, impl_dyn_multi, &ty);
-        self.maybe_recover_from_bad_type_plus(allow_plus, &ty)?;
-        let ty = self.maybe_recover_from_question_mark(ty, recover_question_mark);
-        self.maybe_recover_from_bad_qpath(ty, allow_qpath_recovery)
+        if matches!(allow_plus, AllowPlus::Yes) {
+            self.maybe_recover_from_bad_type_plus(&ty)?;
+        } else {
+            self.maybe_report_ambiguous_plus(impl_dyn_multi, &ty);
+        }
+        if let RecoverQuestionMark::Yes = recover_question_mark {
+            ty = self.maybe_recover_from_question_mark(ty);
+        }
+        if allow_qpath_recovery { self.maybe_recover_from_bad_qpath(ty) } else { Ok(ty) }
     }
 
     /// Parses either:
@@ -474,7 +479,7 @@
             err.span_suggestion(
                 span,
                 "place `mut` before `dyn`",
-                "&mut dyn".to_string(),
+                "&mut dyn",
                 Applicability::MachineApplicable,
             );
             err.emit();
@@ -518,6 +523,7 @@
             kind: rustc_ast::VisibilityKind::Inherited,
             tokens: None,
         };
+        let span_start = self.token.span;
         let ast::FnHeader { ext, unsafety, constness, asyncness } =
             self.parse_fn_front_matter(&inherited_vis)?;
         let decl = self.parse_fn_decl(|_| false, AllowPlus::No, recover_return_sign)?;
@@ -531,7 +537,8 @@
         if let ast::Async::Yes { span, .. } = asyncness {
             self.error_fn_ptr_bad_qualifier(whole_span, span, "async");
         }
-        Ok(TyKind::BareFn(P(BareFnTy { ext, unsafety, generic_params: params, decl })))
+        let decl_span = span_start.to(self.token.span);
+        Ok(TyKind::BareFn(P(BareFnTy { ext, unsafety, generic_params: params, decl, decl_span })))
     }
 
     /// Emit an error for the given bad function pointer qualifier.
@@ -541,7 +548,7 @@
             .span_suggestion_short(
                 qual_span,
                 &format!("remove the `{}` qualifier", qual),
-                String::new(),
+                "",
                 Applicability::MaybeIncorrect,
             )
             .emit();
@@ -641,7 +648,7 @@
                     .span_suggestion(
                         self.token.span,
                         "remove this keyword",
-                        String::new(),
+                        "",
                         Applicability::MachineApplicable,
                     )
                     .emit();
diff --git a/compiler/rustc_passes/Cargo.toml b/compiler/rustc_passes/Cargo.toml
index a3ef198..676812d 100644
--- a/compiler/rustc_passes/Cargo.toml
+++ b/compiler/rustc_passes/Cargo.toml
@@ -5,6 +5,7 @@
 
 [dependencies]
 tracing = "0.1"
+itertools = "0.10.1"
 rustc_middle = { path = "../rustc_middle" }
 rustc_attr = { path = "../rustc_attr" }
 rustc_data_structures = { path = "../rustc_data_structures" }
@@ -12,7 +13,6 @@
 rustc_expand = { path = "../rustc_expand" }
 rustc_hir = { path = "../rustc_hir" }
 rustc_index = { path = "../rustc_index" }
-rustc_parse = { path = "../rustc_parse" }
 rustc_session = { path = "../rustc_session" }
 rustc_target = { path = "../rustc_target" }
 rustc_ast = { path = "../rustc_ast" }
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index 72cbdbc..536d45b 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -7,6 +7,7 @@
 use rustc_ast::{ast, AttrStyle, Attribute, Lit, LitKind, MetaItemKind, NestedMetaItem};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::{pluralize, struct_span_err, Applicability, MultiSpan};
+use rustc_expand::base::resolve_path;
 use rustc_feature::{AttributeDuplicates, AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
 use rustc_hir as hir;
 use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
@@ -22,6 +23,7 @@
 use rustc_session::parse::feature_err;
 use rustc_span::symbol::{kw, sym, Symbol};
 use rustc_span::{Span, DUMMY_SP};
+use rustc_target::spec::abi::Abi;
 use std::collections::hash_map::Entry;
 
 pub(crate) fn target_from_impl_item<'tcx>(
@@ -74,6 +76,7 @@
         for attr in attrs {
             let attr_is_valid = match attr.name_or_empty() {
                 sym::inline => self.check_inline(hir_id, attr, span, target),
+                sym::no_coverage => self.check_no_coverage(hir_id, attr, span, target),
                 sym::non_exhaustive => self.check_non_exhaustive(hir_id, attr, span, target),
                 sym::marker => self.check_marker(hir_id, attr, span, target),
                 sym::rustc_must_implement_one_of => {
@@ -114,14 +117,15 @@
                 sym::rustc_lint_query_instability => {
                     self.check_rustc_lint_query_instability(&attr, span, target)
                 }
+                sym::rustc_lint_diagnostics => {
+                    self.check_rustc_lint_diagnostics(&attr, span, target)
+                }
                 sym::rustc_clean
                 | sym::rustc_dirty
                 | sym::rustc_if_this_changed
                 | sym::rustc_then_this_would_need => self.check_rustc_dirty_clean(&attr),
                 sym::cmse_nonsecure_entry => self.check_cmse_nonsecure_entry(attr, span, target),
-                sym::default_method_body_is_const => {
-                    self.check_default_method_body_is_const(attr, span, target)
-                }
+                sym::const_trait => self.check_const_trait(attr, span, target),
                 sym::must_not_suspend => self.check_must_not_suspend(&attr, span, target),
                 sym::must_use => self.check_must_use(hir_id, &attr, span, target),
                 sym::rustc_pass_by_value => self.check_pass_by_value(&attr, span, target),
@@ -147,9 +151,7 @@
                 sym::link_name => self.check_link_name(hir_id, attr, span, target),
                 sym::link_section => self.check_link_section(hir_id, attr, span, target),
                 sym::no_mangle => self.check_no_mangle(hir_id, attr, span, target),
-                sym::deprecated | sym::rustc_deprecated => {
-                    self.check_deprecated(hir_id, attr, span, target)
-                }
+                sym::deprecated => self.check_deprecated(hir_id, attr, span, target),
                 sym::macro_use | sym::macro_escape => self.check_macro_use(hir_id, attr, target),
                 sym::path => self.check_generic_attr(hir_id, attr, target, &[Target::Mod]),
                 sym::plugin_registrar => self.check_plugin_registrar(hir_id, attr, target),
@@ -290,6 +292,57 @@
         }
     }
 
+    /// Checks if a `#[no_coverage]` is applied directly to a function
+    fn check_no_coverage(
+        &self,
+        hir_id: HirId,
+        attr: &Attribute,
+        span: Span,
+        target: Target,
+    ) -> bool {
+        match target {
+            // no_coverage on function is fine
+            Target::Fn
+            | Target::Closure
+            | Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => true,
+
+            // function prototypes can't be covered
+            Target::Method(MethodKind::Trait { body: false }) | Target::ForeignFn => {
+                self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
+                    lint.build("`#[no_coverage]` is ignored on function prototypes").emit();
+                });
+                true
+            }
+
+            Target::Mod | Target::ForeignMod | Target::Impl | Target::Trait => {
+                self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
+                    lint.build("`#[no_coverage]` does not propagate into items and must be applied to the contained functions directly").emit();
+                });
+                true
+            }
+
+            Target::Expression | Target::Statement | Target::Arm => {
+                self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
+                    lint.build("`#[no_coverage]` may only be applied to function definitions")
+                        .emit();
+                });
+                true
+            }
+
+            _ => {
+                struct_span_err!(
+                    self.tcx.sess,
+                    attr.span,
+                    E0788,
+                    "`#[no_coverage]` must be applied to coverable code",
+                )
+                .span_label(span, "not coverable code")
+                .emit();
+                false
+            }
+        }
+    }
+
     fn check_generic_attr(
         &self,
         hir_id: HirId,
@@ -751,6 +804,37 @@
         true
     }
 
+    fn check_doc_tuple_variadic(&self, meta: &NestedMetaItem, hir_id: HirId) -> bool {
+        match self.tcx.hir().find(hir_id).and_then(|node| match node {
+            hir::Node::Item(item) => Some(&item.kind),
+            _ => None,
+        }) {
+            Some(ItemKind::Impl(ref i)) => {
+                if !matches!(&i.self_ty.kind, hir::TyKind::Tup([_])) {
+                    self.tcx
+                        .sess
+                        .struct_span_err(
+                            meta.span(),
+                            "`#[doc(tuple_variadic)]` must be used on the first of a set of tuple trait impls with varying arity",
+                        )
+                        .emit();
+                    return false;
+                }
+            }
+            _ => {
+                self.tcx
+                    .sess
+                    .struct_span_err(
+                        meta.span(),
+                        "`#[doc(keyword = \"...\")]` can only be used on impl blocks",
+                    )
+                    .emit();
+                return false;
+            }
+        }
+        true
+    }
+
     /// Checks `#[doc(inline)]`/`#[doc(no_inline)]` attributes. Returns `true` if valid.
     ///
     /// A doc inlining attribute is invalid if it is applied to a non-`use` item, or
@@ -949,6 +1033,13 @@
                             is_valid = false
                         }
 
+                        sym::tuple_variadic
+                            if !self.check_attr_not_crate_level(meta, hir_id, "tuple_variadic")
+                                || !self.check_doc_tuple_variadic(meta, hir_id) =>
+                        {
+                            is_valid = false
+                        }
+
                         sym::html_favicon_url
                         | sym::html_logo_url
                         | sym::html_playground_url
@@ -993,7 +1084,8 @@
                         | sym::no_inline
                         | sym::notable_trait
                         | sym::passes
-                        | sym::plugins => {}
+                        | sym::plugins
+                        | sym::tuple_variadic => {}
 
                         sym::test => {
                             if !self.check_test_attr(meta, hir_id) {
@@ -1034,7 +1126,7 @@
                                         diag.span_suggestion_short(
                                             i_meta.span,
                                             "use `notable_trait` instead",
-                                            String::from("notable_trait"),
+                                            "notable_trait",
                                             Applicability::MachineApplicable,
                                         );
                                         diag.note("`doc(spotlight)` is now a no-op");
@@ -1245,22 +1337,27 @@
 
     /// Checks if `#[link]` is applied to an item other than a foreign module.
     fn check_link(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) {
-        match target {
-            Target::ForeignMod => {}
-            _ => {
-                self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
-                    let mut diag = lint.build("attribute should be applied to an `extern` block");
-                    diag.warn(
-                        "this was previously accepted by the compiler but is \
-                         being phased out; it will become a hard error in \
-                         a future release!",
-                    );
-
-                    diag.span_label(span, "not an `extern` block");
-                    diag.emit();
-                });
-            }
+        if target == Target::ForeignMod
+            && let hir::Node::Item(item) = self.tcx.hir().get(hir_id)
+            && let Item { kind: ItemKind::ForeignMod { abi, .. }, .. } = item
+            && !matches!(abi, Abi::Rust | Abi::RustIntrinsic | Abi::PlatformIntrinsic)
+        {
+            return;
         }
+
+        self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
+            let mut diag =
+                lint.build("attribute should be applied to an `extern` block with non-Rust ABI");
+            diag.warn(
+                "this was previously accepted by the compiler but is \
+                 being phased out; it will become a hard error in \
+                 a future release!",
+            );
+            if target != Target::ForeignMod {
+                diag.span_label(span, "not an `extern` block");
+            }
+            diag.emit();
+        });
     }
 
     /// Checks if `#[link_name]` is applied to an item other than a foreign function or static.
@@ -1495,12 +1592,9 @@
         }
     }
 
-    fn check_rustc_lint_query_instability(
-        &self,
-        attr: &Attribute,
-        span: Span,
-        target: Target,
-    ) -> bool {
+    /// Helper function for checking that the provided attribute is only applied to a function or
+    /// method.
+    fn check_applied_to_fn_or_method(&self, attr: &Attribute, span: Span, target: Target) -> bool {
         let is_function = matches!(target, Target::Fn | Target::Method(..));
         if !is_function {
             self.tcx
@@ -1514,6 +1608,23 @@
         }
     }
 
+    /// Checks that the `#[rustc_lint_query_instability]` attribute is only applied to a function
+    /// or method.
+    fn check_rustc_lint_query_instability(
+        &self,
+        attr: &Attribute,
+        span: Span,
+        target: Target,
+    ) -> bool {
+        self.check_applied_to_fn_or_method(attr, span, target)
+    }
+
+    /// Checks that the `#[rustc_lint_diagnostics]` attribute is only applied to a function or
+    /// method.
+    fn check_rustc_lint_diagnostics(&self, attr: &Attribute, span: Span, target: Target) -> bool {
+        self.check_applied_to_fn_or_method(attr, span, target)
+    }
+
     /// Checks that the dep-graph debugging attributes are only present when the query-dep-graph
     /// option is passed to the compiler.
     fn check_rustc_dirty_clean(&self, attr: &Attribute) -> bool {
@@ -1591,7 +1702,7 @@
                     .span_suggestion(
                         attr.span,
                         "remove this attribute",
-                        String::new(),
+                        "",
                         Applicability::MachineApplicable,
                     )
                     .emit();
@@ -1904,49 +2015,64 @@
             }
         }
 
-        let hints = match attr.meta_item_list() {
-            Some(meta_item_list) => meta_item_list,
-            None => {
-                self.emit_debugger_visualizer_err(attr);
-                return false;
-            }
+        let Some(hints) = attr.meta_item_list() else {
+            self.emit_debugger_visualizer_err(attr.span);
+            return false;
         };
 
         let hint = match hints.len() {
             1 => &hints[0],
             _ => {
-                self.emit_debugger_visualizer_err(attr);
+                self.emit_debugger_visualizer_err(attr.span);
                 return false;
             }
         };
 
-        if !hint.has_name(sym::natvis_file) {
-            self.emit_debugger_visualizer_err(attr);
+        let Some(meta_item) = hint.meta_item() else {
+            self.emit_debugger_visualizer_err(attr.span);
             return false;
-        }
+        };
 
-        let meta_item = match hint.meta_item() {
-            Some(meta_item) => meta_item,
-            None => {
-                self.emit_debugger_visualizer_err(attr);
+        let visualizer_path = match (meta_item.name_or_empty(), meta_item.value_str()) {
+            (sym::natvis_file, Some(value)) => value,
+            (sym::gdb_script_file, Some(value)) => value,
+            (_, _) => {
+                self.emit_debugger_visualizer_err(meta_item.span);
                 return false;
             }
         };
 
-        match (meta_item.name_or_empty(), meta_item.value_str()) {
-            (sym::natvis_file, Some(_)) => true,
-            (_, _) => {
-                self.emit_debugger_visualizer_err(attr);
+        let file =
+            match resolve_path(&self.tcx.sess.parse_sess, visualizer_path.as_str(), attr.span) {
+                Ok(file) => file,
+                Err(mut err) => {
+                    err.emit();
+                    return false;
+                }
+            };
+
+        match std::fs::File::open(&file) {
+            Ok(_) => true,
+            Err(err) => {
+                self.tcx
+                    .sess
+                    .struct_span_err(
+                        meta_item.span,
+                        &format!("couldn't read {}: {}", file.display(), err),
+                    )
+                    .emit();
                 false
             }
         }
     }
 
-    fn emit_debugger_visualizer_err(&self, attr: &Attribute) {
+    fn emit_debugger_visualizer_err(&self, span: Span) {
         self.tcx
             .sess
-            .struct_span_err(attr.span, "invalid argument")
+            .struct_span_err(span, "invalid argument")
             .note(r#"expected: `natvis_file = "..."`"#)
+            .note(r#"OR"#)
+            .note(r#"expected: `gdb_script_file = "..."`"#)
             .emit();
     }
 
@@ -2003,23 +2129,14 @@
         }
     }
 
-    /// default_method_body_is_const should only be applied to trait methods with default bodies.
-    fn check_default_method_body_is_const(
-        &self,
-        attr: &Attribute,
-        span: Span,
-        target: Target,
-    ) -> bool {
+    /// `#[const_trait]` only applies to traits.
+    fn check_const_trait(&self, attr: &Attribute, _span: Span, target: Target) -> bool {
         match target {
-            Target::Method(MethodKind::Trait { body: true }) => true,
+            Target::Trait => true,
             _ => {
                 self.tcx
                     .sess
-                    .struct_span_err(
-                        attr.span,
-                        "attribute should be applied to a trait method with body",
-                    )
-                    .span_label(span, "not a trait method or missing a body")
+                    .struct_span_err(attr.span, "attribute should be applied to a trait")
                     .emit();
                 false
             }
@@ -2113,6 +2230,8 @@
                 "attribute `{}` without any lints has no effect",
                 attr.name_or_empty()
             )
+        } else if attr.name_or_empty() == sym::default_method_body_is_const {
+            format!("`default_method_body_is_const` has been replaced with `#[const_trait]` on traits")
         } else {
             return;
         };
@@ -2122,7 +2241,7 @@
                 .span_suggestion(
                     attr.span,
                     "remove this attribute",
-                    String::new(),
+                    "",
                     Applicability::MachineApplicable,
                 )
                 .note(&note)
@@ -2203,7 +2322,7 @@
 
     fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
         let target = match expr.kind {
-            hir::ExprKind::Closure(..) => Target::Closure,
+            hir::ExprKind::Closure { .. } => Target::Closure,
             _ => Target::Expression,
         };
 
@@ -2312,7 +2431,7 @@
 
 fn check_mod_attrs(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
     let check_attr_visitor = &mut CheckAttrVisitor { tcx };
-    tcx.hir().visit_item_likes_in_module(module_def_id, &mut check_attr_visitor.as_deep_visitor());
+    tcx.hir().deep_visit_item_likes_in_module(module_def_id, check_attr_visitor);
     if module_def_id.is_top_level_module() {
         check_attr_visitor.check_attributes(CRATE_HIR_ID, DUMMY_SP, Target::Mod, None);
         check_invalid_crate_level_attr(tcx, tcx.hir().krate_attrs());
@@ -2350,7 +2469,7 @@
                         db.span_note(other, "attribute also specified here").span_suggestion(
                             this,
                             "remove this attribute",
-                            String::new(),
+                            "",
                             Applicability::MachineApplicable,
                         );
                         if matches!(duplicates, FutureWarnFollowing | FutureWarnPreceding) {
@@ -2385,7 +2504,7 @@
                     .span_suggestion(
                         this,
                         "remove this attribute",
-                        String::new(),
+                        "",
                         Applicability::MachineApplicable,
                     )
                     .emit();
diff --git a/compiler/rustc_passes/src/check_const.rs b/compiler/rustc_passes/src/check_const.rs
index 15e2429..996ca66 100644
--- a/compiler/rustc_passes/src/check_const.rs
+++ b/compiler/rustc_passes/src/check_const.rs
@@ -13,7 +13,6 @@
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_middle::hir::nested_filter;
-use rustc_middle::ty;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::parse::feature_err;
@@ -57,91 +56,13 @@
 
 fn check_mod_const_bodies(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
     let mut vis = CheckConstVisitor::new(tcx);
-    tcx.hir().visit_item_likes_in_module(module_def_id, &mut vis.as_deep_visitor());
-    tcx.hir().visit_item_likes_in_module(module_def_id, &mut CheckConstTraitVisitor::new(tcx));
+    tcx.hir().deep_visit_item_likes_in_module(module_def_id, &mut vis);
 }
 
 pub(crate) fn provide(providers: &mut Providers) {
     *providers = Providers { check_mod_const_bodies, ..*providers };
 }
 
-struct CheckConstTraitVisitor<'tcx> {
-    tcx: TyCtxt<'tcx>,
-}
-
-impl<'tcx> CheckConstTraitVisitor<'tcx> {
-    fn new(tcx: TyCtxt<'tcx>) -> Self {
-        CheckConstTraitVisitor { tcx }
-    }
-}
-
-impl<'tcx> hir::itemlikevisit::ItemLikeVisitor<'tcx> for CheckConstTraitVisitor<'tcx> {
-    /// check for const trait impls, and errors if the impl uses provided/default functions
-    /// of the trait being implemented; as those provided functions can be non-const.
-    fn visit_item<'hir>(&mut self, item: &'hir hir::Item<'hir>) {
-        let _: Option<_> = try {
-            if let hir::ItemKind::Impl(ref imp) = item.kind && let hir::Constness::Const = imp.constness {
-                    let trait_def_id = imp.of_trait.as_ref()?.trait_def_id()?;
-                    let ancestors = self
-                        .tcx
-                        .trait_def(trait_def_id)
-                        .ancestors(self.tcx, item.def_id.to_def_id())
-                        .ok()?;
-                    let mut to_implement = Vec::new();
-
-                    for trait_item in self.tcx.associated_items(trait_def_id).in_definition_order()
-                    {
-                        if let ty::AssocItem {
-                            kind: ty::AssocKind::Fn,
-                            defaultness,
-                            def_id: trait_item_id,
-                            ..
-                        } = *trait_item
-                        {
-                            // we can ignore functions that do not have default bodies:
-                            // if those are unimplemented it will be caught by typeck.
-                            if !defaultness.has_value()
-                                || self
-                                    .tcx
-                                    .has_attr(trait_item_id, sym::default_method_body_is_const)
-                            {
-                                continue;
-                            }
-
-                            let is_implemented = ancestors
-                                .leaf_def(self.tcx, trait_item_id)
-                                .map(|node_item| !node_item.defining_node.is_from_trait())
-                                .unwrap_or(false);
-
-                            if !is_implemented {
-                                to_implement.push(self.tcx.item_name(trait_item_id).to_string());
-                            }
-                        }
-                    }
-
-                    // all nonconst trait functions (not marked with #[default_method_body_is_const])
-                    // must be implemented
-                    if !to_implement.is_empty() {
-                        self.tcx
-                            .sess
-                            .struct_span_err(
-                                item.span,
-                                "const trait implementations may not use non-const default functions",
-                            )
-                            .note(&format!("`{}` not implemented", to_implement.join("`, `")))
-                            .emit();
-                    }
-            }
-        };
-    }
-
-    fn visit_trait_item<'hir>(&mut self, _: &'hir hir::TraitItem<'hir>) {}
-
-    fn visit_impl_item<'hir>(&mut self, _: &'hir hir::ImplItem<'hir>) {}
-
-    fn visit_foreign_item<'hir>(&mut self, _: &'hir hir::ForeignItem<'hir>) {}
-}
-
 #[derive(Copy, Clone)]
 struct CheckConstVisitor<'tcx> {
     tcx: TyCtxt<'tcx>,
@@ -270,6 +191,10 @@
         self.tcx.hir()
     }
 
+    fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
+        intravisit::walk_item(self, item);
+    }
+
     fn visit_anon_const(&mut self, anon: &'tcx hir::AnonConst) {
         let kind = Some(hir::ConstContext::Const);
         self.recurse_into(kind, None, |this| intravisit::walk_anon_const(this, anon));
diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs
index df28ea4..01d93f6 100644
--- a/compiler/rustc_passes/src/dead.rs
+++ b/compiler/rustc_passes/src/dead.rs
@@ -2,13 +2,13 @@
 // closely. The idea is that all reachable symbols are live, codes called
 // from live codes are live, and everything else is dead.
 
+use itertools::Itertools;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_errors::pluralize;
+use rustc_errors::{pluralize, MultiSpan};
 use rustc_hir as hir;
 use rustc_hir::def::{CtorOf, DefKind, Res};
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::intravisit::{self, Visitor};
-use rustc_hir::itemlikevisit::ItemLikeVisitor;
 use rustc_hir::{Node, PatKind, TyKind};
 use rustc_middle::hir::nested_filter;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
@@ -184,10 +184,10 @@
             }
         }
 
-        if let hir::ExprKind::Assign(lhs, rhs, _) = assign.kind {
-            if check_for_self_assign_helper(self.typeck_results(), lhs, rhs)
+        if let hir::ExprKind::Assign(lhs, rhs, _) = assign.kind
+            && check_for_self_assign_helper(self.typeck_results(), lhs, rhs)
                 && !assign.span.from_expansion()
-            {
+        {
                 let is_field_assign = matches!(lhs.kind, hir::ExprKind::Field(..));
                 self.tcx.struct_span_lint_hir(
                     lint::builtin::DEAD_CODE,
@@ -202,7 +202,6 @@
                         .emit();
                     },
                 )
-            }
         }
     }
 
@@ -252,19 +251,19 @@
                 return false;
             }
 
-            if let Some(trait_of) = self.tcx.trait_id_of_impl(impl_of) {
-                if self.tcx.has_attr(trait_of, sym::rustc_trivial_field_reads) {
-                    let trait_ref = self.tcx.impl_trait_ref(impl_of).unwrap();
-                    if let ty::Adt(adt_def, _) = trait_ref.self_ty().kind() {
-                        if let Some(adt_def_id) = adt_def.did().as_local() {
-                            self.ignored_derived_traits
-                                .entry(adt_def_id)
-                                .or_default()
-                                .push((trait_of, impl_of));
-                        }
-                    }
-                    return true;
+            if let Some(trait_of) = self.tcx.trait_id_of_impl(impl_of)
+                && self.tcx.has_attr(trait_of, sym::rustc_trivial_field_reads)
+            {
+                let trait_ref = self.tcx.impl_trait_ref(impl_of).unwrap();
+                if let ty::Adt(adt_def, _) = trait_ref.self_ty().kind()
+                    && let Some(adt_def_id) = adt_def.did().as_local()
+                {
+                    self.ignored_derived_traits
+                        .entry(adt_def_id)
+                        .or_default()
+                        .push((trait_of, impl_of));
                 }
+                return true;
             }
         }
 
@@ -272,13 +271,10 @@
     }
 
     fn visit_node(&mut self, node: Node<'tcx>) {
-        if let Some(item_def_id) = match node {
-            Node::ImplItem(hir::ImplItem { def_id, .. }) => Some(def_id.to_def_id()),
-            _ => None,
-        } {
-            if self.should_ignore_item(item_def_id) {
-                return;
-            }
+        if let Node::ImplItem(hir::ImplItem { def_id, .. }) = node
+            && self.should_ignore_item(def_id.to_def_id())
+        {
+            return;
         }
 
         let had_repr_c = self.repr_has_repr_c;
@@ -468,7 +464,7 @@
     tcx.lint_level_at_node(lint::builtin::DEAD_CODE, id).0 == lint::Allow
 }
 
-// This visitor seeds items that
+// These check_* functions seeds items that
 //   1) We want to explicitly consider as live:
 //     * Item annotated with #[allow(dead_code)]
 //         - This is done so that if we want to suppress warnings for a
@@ -481,82 +477,95 @@
 //   or
 //   2) We are not sure to be live or not
 //     * Implementations of traits and trait methods
-struct LifeSeeder<'tcx> {
-    worklist: Vec<LocalDefId>,
+fn check_item<'tcx>(
     tcx: TyCtxt<'tcx>,
-    // see `MarkSymbolVisitor::struct_constructors`
-    struct_constructors: FxHashMap<LocalDefId, LocalDefId>,
-}
+    worklist: &mut Vec<LocalDefId>,
+    struct_constructors: &mut FxHashMap<LocalDefId, LocalDefId>,
+    id: hir::ItemId,
+) {
+    let allow_dead_code = has_allow_dead_code_or_lang_attr(tcx, id.hir_id());
+    if allow_dead_code {
+        worklist.push(id.def_id);
+    }
 
-impl<'v, 'tcx> ItemLikeVisitor<'v> for LifeSeeder<'tcx> {
-    fn visit_item(&mut self, item: &hir::Item<'_>) {
-        let allow_dead_code = has_allow_dead_code_or_lang_attr(self.tcx, item.hir_id());
-        if allow_dead_code {
-            self.worklist.push(item.def_id);
-        }
-        match item.kind {
-            hir::ItemKind::Enum(ref enum_def, _) => {
-                let hir = self.tcx.hir();
+    match tcx.def_kind(id.def_id) {
+        DefKind::Enum => {
+            let item = tcx.hir().item(id);
+            if let hir::ItemKind::Enum(ref enum_def, _) = item.kind {
+                let hir = tcx.hir();
                 if allow_dead_code {
-                    self.worklist.extend(
+                    worklist.extend(
                         enum_def.variants.iter().map(|variant| hir.local_def_id(variant.id)),
                     );
                 }
 
                 for variant in enum_def.variants {
                     if let Some(ctor_hir_id) = variant.data.ctor_hir_id() {
-                        self.struct_constructors
+                        struct_constructors
                             .insert(hir.local_def_id(ctor_hir_id), hir.local_def_id(variant.id));
                     }
                 }
             }
-            hir::ItemKind::Impl(hir::Impl { ref of_trait, items, .. }) => {
-                if of_trait.is_some() {
-                    self.worklist.push(item.def_id);
-                }
-                for impl_item_ref in *items {
-                    let impl_item = self.tcx.hir().impl_item(impl_item_ref.id);
-                    if of_trait.is_some()
-                        || has_allow_dead_code_or_lang_attr(self.tcx, impl_item.hir_id())
-                    {
-                        self.worklist.push(impl_item_ref.id.def_id);
-                    }
-                }
-            }
-            hir::ItemKind::Struct(ref variant_data, _) => {
-                if let Some(ctor_hir_id) = variant_data.ctor_hir_id() {
-                    self.struct_constructors
-                        .insert(self.tcx.hir().local_def_id(ctor_hir_id), item.def_id);
-                }
-            }
-            hir::ItemKind::GlobalAsm(_) => {
-                // global_asm! is always live.
-                self.worklist.push(item.def_id);
-            }
-            _ => (),
         }
-    }
+        DefKind::Impl => {
+            let of_trait = tcx.impl_trait_ref(id.def_id);
 
-    fn visit_trait_item(&mut self, trait_item: &hir::TraitItem<'_>) {
-        use hir::TraitItemKind::{Const, Fn};
+            if of_trait.is_some() {
+                worklist.push(id.def_id);
+            }
+
+            // get DefIds from another query
+            let local_def_ids = tcx
+                .associated_item_def_ids(id.def_id)
+                .iter()
+                .filter_map(|def_id| def_id.as_local());
+
+            // And we access the Map here to get HirId from LocalDefId
+            for id in local_def_ids {
+                if of_trait.is_some()
+                    || has_allow_dead_code_or_lang_attr(tcx, tcx.hir().local_def_id_to_hir_id(id))
+                {
+                    worklist.push(id);
+                }
+            }
+        }
+        DefKind::Struct => {
+            let item = tcx.hir().item(id);
+            if let hir::ItemKind::Struct(ref variant_data, _) = item.kind
+                && let Some(ctor_hir_id) = variant_data.ctor_hir_id()
+            {
+                struct_constructors.insert(tcx.hir().local_def_id(ctor_hir_id), item.def_id);
+            }
+        }
+        DefKind::GlobalAsm => {
+            // global_asm! is always live.
+            worklist.push(id.def_id);
+        }
+        _ => {}
+    }
+}
+
+fn check_trait_item<'tcx>(tcx: TyCtxt<'tcx>, worklist: &mut Vec<LocalDefId>, id: hir::TraitItemId) {
+    use hir::TraitItemKind::{Const, Fn};
+    if matches!(tcx.def_kind(id.def_id), DefKind::AssocConst | DefKind::AssocFn) {
+        let trait_item = tcx.hir().trait_item(id);
         if matches!(trait_item.kind, Const(_, Some(_)) | Fn(_, hir::TraitFn::Provided(_)))
-            && has_allow_dead_code_or_lang_attr(self.tcx, trait_item.hir_id())
+            && has_allow_dead_code_or_lang_attr(tcx, trait_item.hir_id())
         {
-            self.worklist.push(trait_item.def_id);
+            worklist.push(trait_item.def_id);
         }
     }
+}
 
-    fn visit_impl_item(&mut self, _item: &hir::ImplItem<'_>) {
-        // ignore: we are handling this in `visit_item` above
-    }
-
-    fn visit_foreign_item(&mut self, foreign_item: &hir::ForeignItem<'_>) {
-        use hir::ForeignItemKind::{Fn, Static};
-        if matches!(foreign_item.kind, Static(..) | Fn(..))
-            && has_allow_dead_code_or_lang_attr(self.tcx, foreign_item.hir_id())
-        {
-            self.worklist.push(foreign_item.def_id);
-        }
+fn check_foreign_item<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    worklist: &mut Vec<LocalDefId>,
+    id: hir::ForeignItemId,
+) {
+    if matches!(tcx.def_kind(id.def_id), DefKind::Static(_) | DefKind::Fn)
+        && has_allow_dead_code_or_lang_attr(tcx, id.hir_id())
+    {
+        worklist.push(id.def_id);
     }
 }
 
@@ -564,7 +573,9 @@
     tcx: TyCtxt<'tcx>,
 ) -> (Vec<LocalDefId>, FxHashMap<LocalDefId, LocalDefId>) {
     let access_levels = &tcx.privacy_access_levels(());
-    let worklist = access_levels
+    // see `MarkSymbolVisitor::struct_constructors`
+    let mut struct_constructors = Default::default();
+    let mut worklist = access_levels
         .map
         .iter()
         .filter_map(
@@ -576,11 +587,20 @@
         .chain(tcx.entry_fn(()).and_then(|(def_id, _)| def_id.as_local()))
         .collect::<Vec<_>>();
 
-    // Seed implemented trait items
-    let mut life_seeder = LifeSeeder { worklist, tcx, struct_constructors: Default::default() };
-    tcx.hir().visit_all_item_likes(&mut life_seeder);
+    let crate_items = tcx.hir_crate_items(());
+    for id in crate_items.items() {
+        check_item(tcx, &mut worklist, &mut struct_constructors, id);
+    }
 
-    (life_seeder.worklist, life_seeder.struct_constructors)
+    for id in crate_items.trait_items() {
+        check_trait_item(tcx, &mut worklist, id);
+    }
+
+    for id in crate_items.foreign_items() {
+        check_foreign_item(tcx, &mut worklist, id);
+    }
+
+    (worklist, struct_constructors)
 }
 
 fn live_symbols_and_ignored_derived_traits<'tcx>(
@@ -603,6 +623,13 @@
     (symbol_visitor.live_symbols, symbol_visitor.ignored_derived_traits)
 }
 
+struct DeadVariant {
+    hir_id: hir::HirId,
+    span: Span,
+    name: Symbol,
+    level: lint::Level,
+}
+
 struct DeadVisitor<'tcx> {
     tcx: TyCtxt<'tcx>,
     live_symbols: &'tcx FxHashSet<LocalDefId>,
@@ -654,16 +681,121 @@
         let inherent_impls = self.tcx.inherent_impls(def_id);
         for &impl_did in inherent_impls.iter() {
             for item_did in self.tcx.associated_item_def_ids(impl_did) {
-                if let Some(def_id) = item_did.as_local() {
-                    if self.live_symbols.contains(&def_id) {
-                        return true;
-                    }
+                if let Some(def_id) = item_did.as_local()
+                    && self.live_symbols.contains(&def_id)
+                {
+                    return true;
                 }
             }
         }
         false
     }
 
+    fn warn_multiple_dead_codes(
+        &self,
+        dead_codes: &[(hir::HirId, Span, Symbol)],
+        participle: &str,
+        parent_hir_id: Option<hir::HirId>,
+    ) {
+        if let Some((id, _, name)) = dead_codes.first()
+            && !name.as_str().starts_with('_')
+        {
+            self.tcx.struct_span_lint_hir(
+                lint::builtin::DEAD_CODE,
+                *id,
+                MultiSpan::from_spans(
+                    dead_codes.iter().map(|(_, span, _)| *span).collect(),
+                ),
+                |lint| {
+                    let def_id = self.tcx.hir().local_def_id(*id);
+                    let descr = self.tcx.def_kind(def_id).descr(def_id.to_def_id());
+                    let span_len = dead_codes.len();
+                    let names = match &dead_codes.iter().map(|(_, _, n)| n.to_string()).collect::<Vec<_>>()[..]
+                    {
+                        _ if span_len > 6 => String::new(),
+                        [name] => format!("`{name}` "),
+                        [names @ .., last] => {
+                            format!("{} and `{last}` ", names.iter().map(|name| format!("`{name}`")).join(", "))
+                        }
+                        [] => unreachable!(),
+                    };
+                    let mut err = lint.build(&format!(
+                        "{these}{descr}{s} {names}{are} never {participle}",
+                        these = if span_len > 6 { "multiple " } else { "" },
+                        s = pluralize!(span_len),
+                        are = pluralize!("is", span_len),
+                    ));
+                    let hir = self.tcx.hir();
+                    if let Some(parent_hir_id) = parent_hir_id
+                        && let Some(parent_node) = hir.find(parent_hir_id)
+                        && let Node::Item(item) = parent_node
+                    {
+                        let def_id = self.tcx.hir().local_def_id(parent_hir_id);
+                        let parent_descr = self.tcx.def_kind(def_id).descr(def_id.to_def_id());
+                        err.span_label(
+                            item.ident.span,
+                            format!(
+                                "{descr}{s} in this {parent_descr}",
+                                s = pluralize!(span_len)
+                            ),
+                        );
+                    }
+                    if let Some(encl_scope) = hir.get_enclosing_scope(*id)
+                        && let Some(encl_def_id) = hir.opt_local_def_id(encl_scope)
+                        && let Some(ign_traits) = self.ignored_derived_traits.get(&encl_def_id)
+                    {
+                        let traits_str = ign_traits
+                            .iter()
+                            .map(|(trait_id, _)| format!("`{}`", self.tcx.item_name(*trait_id)))
+                            .collect::<Vec<_>>()
+                            .join(" and ");
+                        let plural_s = pluralize!(ign_traits.len());
+                        let article = if ign_traits.len() > 1 { "" } else { "a " };
+                        let is_are = if ign_traits.len() > 1 { "these are" } else { "this is" };
+                        let msg = format!(
+                            "`{}` has {}derived impl{} for the trait{} {}, but {} \
+                            intentionally ignored during dead code analysis",
+                            self.tcx.item_name(encl_def_id.to_def_id()),
+                            article,
+                            plural_s,
+                            plural_s,
+                            traits_str,
+                            is_are
+                        );
+                        err.note(&msg);
+                    }
+                        err.emit();
+                    },
+            );
+        }
+    }
+
+    fn warn_dead_fields_and_variants(
+        &self,
+        hir_id: hir::HirId,
+        participle: &str,
+        dead_codes: Vec<DeadVariant>,
+    ) {
+        let mut dead_codes = dead_codes
+            .iter()
+            .filter(|v| !v.name.as_str().starts_with('_'))
+            .map(|v| v)
+            .collect::<Vec<&DeadVariant>>();
+        if dead_codes.is_empty() {
+            return;
+        }
+        dead_codes.sort_by_key(|v| v.level);
+        for (_, group) in &dead_codes.into_iter().group_by(|v| v.level) {
+            self.warn_multiple_dead_codes(
+                &group
+                    .map(|v| (v.hir_id, v.span, v.name))
+                    .collect::<Vec<(hir::HirId, Span, Symbol)>>(),
+                participle,
+                Some(hir_id),
+            );
+        }
+    }
+
     fn warn_dead_code(
         &mut self,
         id: hir::HirId,
@@ -671,43 +803,7 @@
         name: Symbol,
         participle: &str,
     ) {
-        if !name.as_str().starts_with('_') {
-            self.tcx.struct_span_lint_hir(lint::builtin::DEAD_CODE, id, span, |lint| {
-                let def_id = self.tcx.hir().local_def_id(id);
-                let descr = self.tcx.def_kind(def_id).descr(def_id.to_def_id());
-                let mut err = lint.build(&format!("{} is never {}: `{}`", descr, participle, name));
-                let hir = self.tcx.hir();
-                if let Some(encl_scope) = hir.get_enclosing_scope(id)
-                    && let Some(encl_def_id) = hir.opt_local_def_id(encl_scope)
-                    && let Some(ign_traits) = self.ignored_derived_traits.get(&encl_def_id)
-                {
-                    let traits_str = ign_traits
-                        .iter()
-                        .map(|(trait_id, _)| format!("`{}`", self.tcx.item_name(*trait_id)))
-                        .collect::<Vec<_>>()
-                        .join(" and ");
-                    let plural_s = pluralize!(ign_traits.len());
-                    let article = if ign_traits.len() > 1 { "" } else { "a " };
-                    let is_are = if ign_traits.len() > 1 { "these are" } else { "this is" };
-                    let msg = format!(
-                        "`{}` has {}derived impl{} for the trait{} {}, but {} \
-                        intentionally ignored during dead code analysis",
-                        self.tcx.item_name(encl_def_id.to_def_id()),
-                        article,
-                        plural_s,
-                        plural_s,
-                        traits_str,
-                        is_are
-                    );
-                    let multispan = ign_traits
-                        .iter()
-                        .map(|(_, impl_id)| self.tcx.def_span(*impl_id))
-                        .collect::<Vec<_>>();
-                    err.span_note(multispan, &msg);
-                }
-                err.emit();
-            });
-        }
+        self.warn_multiple_dead_codes(&[(id, span, name)], participle, None);
     }
 }
 
@@ -761,15 +857,40 @@
     // This visitor should only visit a single module at a time.
     fn visit_mod(&mut self, _: &'tcx hir::Mod<'tcx>, _: Span, _: hir::HirId) {}
 
+    fn visit_enum_def(
+        &mut self,
+        enum_definition: &'tcx hir::EnumDef<'tcx>,
+        generics: &'tcx hir::Generics<'tcx>,
+        item_id: hir::HirId,
+        _: Span,
+    ) {
+        intravisit::walk_enum_def(self, enum_definition, generics, item_id);
+        let dead_variants = enum_definition
+            .variants
+            .iter()
+            .filter_map(|variant| {
+                if self.should_warn_about_variant(&variant) {
+                    Some(DeadVariant {
+                        hir_id: variant.id,
+                        span: variant.span,
+                        name: variant.ident.name,
+                        level: self.tcx.lint_level_at_node(lint::builtin::DEAD_CODE, variant.id).0,
+                    })
+                } else {
+                    None
+                }
+            })
+            .collect();
+        self.warn_dead_fields_and_variants(item_id, "constructed", dead_variants)
+    }
+
     fn visit_variant(
         &mut self,
         variant: &'tcx hir::Variant<'tcx>,
         g: &'tcx hir::Generics<'tcx>,
         id: hir::HirId,
     ) {
-        if self.should_warn_about_variant(&variant) {
-            self.warn_dead_code(variant.id, variant.span, variant.ident.name, "constructed");
-        } else {
+        if !self.should_warn_about_variant(&variant) {
             intravisit::walk_variant(self, variant, g, id);
         }
     }
@@ -781,11 +902,35 @@
         intravisit::walk_foreign_item(self, fi);
     }
 
-    fn visit_field_def(&mut self, field: &'tcx hir::FieldDef<'tcx>) {
-        if self.should_warn_about_field(&field) {
-            self.warn_dead_code(field.hir_id, field.span, field.ident.name, "read");
-        }
-        intravisit::walk_field_def(self, field);
+    fn visit_variant_data(
+        &mut self,
+        def: &'tcx hir::VariantData<'tcx>,
+        _: Symbol,
+        _: &hir::Generics<'_>,
+        id: hir::HirId,
+        _: rustc_span::Span,
+    ) {
+        intravisit::walk_struct_def(self, def);
+        let dead_fields = def
+            .fields()
+            .iter()
+            .filter_map(|field| {
+                if self.should_warn_about_field(&field) {
+                    Some(DeadVariant {
+                        hir_id: field.hir_id,
+                        span: field.span,
+                        name: field.ident.name,
+                        level: self
+                            .tcx
+                            .lint_level_at_node(lint::builtin::DEAD_CODE, field.hir_id)
+                            .0,
+                    })
+                } else {
+                    None
+                }
+            })
+            .collect();
+        self.warn_dead_fields_and_variants(id, "read", dead_fields)
     }
 
     fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
diff --git a/compiler/rustc_passes/src/debugger_visualizer.rs b/compiler/rustc_passes/src/debugger_visualizer.rs
index f89092c..e08683f 100644
--- a/compiler/rustc_passes/src/debugger_visualizer.rs
+++ b/compiler/rustc_passes/src/debugger_visualizer.rs
@@ -5,8 +5,7 @@
 use rustc_expand::base::resolve_path;
 use rustc_hir as hir;
 use rustc_hir::def_id::CrateNum;
-use rustc_hir::itemlikevisit::ItemLikeVisitor;
-use rustc_hir::{HirId, Target};
+use rustc_hir::HirId;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::TyCtxt;
 use rustc_span::def_id::LOCAL_CRATE;
@@ -14,93 +13,52 @@
 
 use std::sync::Arc;
 
-struct DebuggerVisualizerCollector<'tcx> {
-    debugger_visualizers: FxHashSet<DebuggerVisualizerFile>,
+fn check_for_debugger_visualizer<'tcx>(
     tcx: TyCtxt<'tcx>,
-}
+    hir_id: HirId,
+    debugger_visualizers: &mut FxHashSet<DebuggerVisualizerFile>,
+) {
+    let attrs = tcx.hir().attrs(hir_id);
+    for attr in attrs {
+        if attr.has_name(sym::debugger_visualizer) {
+            let Some(list) = attr.meta_item_list() else {
+                continue
+            };
 
-impl<'v, 'tcx> ItemLikeVisitor<'v> for DebuggerVisualizerCollector<'tcx> {
-    fn visit_item(&mut self, item: &hir::Item<'_>) {
-        let target = Target::from_item(item);
-        match target {
-            Target::Mod => {
-                self.check_for_debugger_visualizer(item.hir_id());
-            }
-            _ => {}
-        }
-    }
-
-    fn visit_trait_item(&mut self, _: &hir::TraitItem<'_>) {}
-
-    fn visit_impl_item(&mut self, _: &hir::ImplItem<'_>) {}
-
-    fn visit_foreign_item(&mut self, _: &hir::ForeignItem<'_>) {}
-}
-
-impl<'tcx> DebuggerVisualizerCollector<'tcx> {
-    fn new(tcx: TyCtxt<'tcx>) -> DebuggerVisualizerCollector<'tcx> {
-        DebuggerVisualizerCollector { tcx, debugger_visualizers: FxHashSet::default() }
-    }
-
-    fn check_for_debugger_visualizer(&mut self, hir_id: HirId) {
-        let attrs = self.tcx.hir().attrs(hir_id);
-        for attr in attrs {
-            if attr.has_name(sym::debugger_visualizer) {
-                let list = match attr.meta_item_list() {
-                    Some(list) => list,
+            let meta_item = match list.len() {
+                1 => match list[0].meta_item() {
+                    Some(meta_item) => meta_item,
                     _ => continue,
-                };
+                },
+                _ => continue,
+            };
 
-                let meta_item = match list.len() {
-                    1 => match list[0].meta_item() {
-                        Some(meta_item) => meta_item,
+            let visualizer_type = match meta_item.name_or_empty() {
+                sym::natvis_file => DebuggerVisualizerType::Natvis,
+                sym::gdb_script_file => DebuggerVisualizerType::GdbPrettyPrinter,
+                _ => continue,
+            };
+
+            let file = match meta_item.value_str() {
+                Some(value) => {
+                    match resolve_path(&tcx.sess.parse_sess, value.as_str(), attr.span) {
+                        Ok(file) => file,
                         _ => continue,
-                    },
-                    _ => continue,
-                };
-
-                let file = match (meta_item.name_or_empty(), meta_item.value_str()) {
-                    (sym::natvis_file, Some(value)) => {
-                        match resolve_path(&self.tcx.sess.parse_sess, value.as_str(), attr.span) {
-                            Ok(file) => file,
-                            Err(mut err) => {
-                                err.emit();
-                                continue;
-                            }
-                        }
                     }
-                    (_, _) => continue,
-                };
+                }
+                None => continue,
+            };
 
-                if file.is_file() {
-                    let contents = match std::fs::read(&file) {
-                        Ok(contents) => contents,
-                        Err(err) => {
-                            self.tcx
-                                .sess
-                                .struct_span_err(
-                                    attr.span,
-                                    &format!(
-                                        "Unable to read contents of file `{}`. {}",
-                                        file.display(),
-                                        err
-                                    ),
-                                )
-                                .emit();
-                            continue;
-                        }
-                    };
-
-                    self.debugger_visualizers.insert(DebuggerVisualizerFile::new(
-                        Arc::from(contents),
-                        DebuggerVisualizerType::Natvis,
-                    ));
-                } else {
-                    self.tcx
-                        .sess
+            match std::fs::read(&file) {
+                Ok(contents) => {
+                    debugger_visualizers
+                        .insert(DebuggerVisualizerFile::new(Arc::from(contents), visualizer_type));
+                }
+                Err(err) => {
+                    tcx.sess
                         .struct_span_err(
-                            attr.span,
-                            &format!("{} is not a valid file", file.display()),
+                            meta_item.span,
+                            &format!("couldn't read {}: {}", file.display(), err),
                         )
                         .emit();
                 }
@@ -114,17 +72,21 @@
     assert_eq!(cnum, LOCAL_CRATE);
 
     // Initialize the collector.
-    let mut collector = DebuggerVisualizerCollector::new(tcx);
+    let mut debugger_visualizers = FxHashSet::default();
 
     // Collect debugger visualizers in this crate.
-    tcx.hir().visit_all_item_likes(&mut collector);
+    tcx.hir().for_each_module(|id| {
+        check_for_debugger_visualizer(
+            tcx,
+            tcx.hir().local_def_id_to_hir_id(id),
+            &mut debugger_visualizers,
+        )
+    });
 
     // Collect debugger visualizers on the crate attributes.
-    collector.check_for_debugger_visualizer(CRATE_HIR_ID);
+    check_for_debugger_visualizer(tcx, CRATE_HIR_ID, &mut debugger_visualizers);
 
     // Extract out the found debugger_visualizer items.
-    let DebuggerVisualizerCollector { debugger_visualizers, .. } = collector;
-
     let mut visualizers = debugger_visualizers.into_iter().collect::<Vec<_>>();
 
     // Sort the visualizers so we always get a deterministic query result.
diff --git a/compiler/rustc_passes/src/diagnostic_items.rs b/compiler/rustc_passes/src/diagnostic_items.rs
index ed694eb..e6b69d8 100644
--- a/compiler/rustc_passes/src/diagnostic_items.rs
+++ b/compiler/rustc_passes/src/diagnostic_items.rs
@@ -10,49 +10,22 @@
 //! * Compiler internal types like `Ty` and `TyCtxt`
 
 use rustc_ast as ast;
-use rustc_hir as hir;
 use rustc_hir::diagnostic_items::DiagnosticItems;
-use rustc_hir::itemlikevisit::ItemLikeVisitor;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::TyCtxt;
 use rustc_span::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
 use rustc_span::symbol::{sym, Symbol};
 
-struct DiagnosticItemCollector<'tcx> {
+fn observe_item<'tcx>(
     tcx: TyCtxt<'tcx>,
-    diagnostic_items: DiagnosticItems,
-}
-
-impl<'v, 'tcx> ItemLikeVisitor<'v> for DiagnosticItemCollector<'tcx> {
-    fn visit_item(&mut self, item: &hir::Item<'_>) {
-        self.observe_item(item.def_id);
-    }
-
-    fn visit_trait_item(&mut self, trait_item: &hir::TraitItem<'_>) {
-        self.observe_item(trait_item.def_id);
-    }
-
-    fn visit_impl_item(&mut self, impl_item: &hir::ImplItem<'_>) {
-        self.observe_item(impl_item.def_id);
-    }
-
-    fn visit_foreign_item(&mut self, foreign_item: &hir::ForeignItem<'_>) {
-        self.observe_item(foreign_item.def_id);
-    }
-}
-
-impl<'tcx> DiagnosticItemCollector<'tcx> {
-    fn new(tcx: TyCtxt<'tcx>) -> DiagnosticItemCollector<'tcx> {
-        DiagnosticItemCollector { tcx, diagnostic_items: DiagnosticItems::default() }
-    }
-
-    fn observe_item(&mut self, def_id: LocalDefId) {
-        let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
-        let attrs = self.tcx.hir().attrs(hir_id);
-        if let Some(name) = extract(attrs) {
-            // insert into our table
-            collect_item(self.tcx, &mut self.diagnostic_items, name, def_id.to_def_id());
-        }
+    diagnostic_items: &mut DiagnosticItems,
+    def_id: LocalDefId,
+) {
+    let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
+    let attrs = tcx.hir().attrs(hir_id);
+    if let Some(name) = extract(attrs) {
+        // insert into our table
+        collect_item(tcx, diagnostic_items, name, def_id.to_def_id());
     }
 }
 
@@ -95,12 +68,28 @@
     assert_eq!(cnum, LOCAL_CRATE);
 
     // Initialize the collector.
-    let mut collector = DiagnosticItemCollector::new(tcx);
+    let mut diagnostic_items = DiagnosticItems::default();
 
     // Collect diagnostic items in this crate.
-    tcx.hir().visit_all_item_likes(&mut collector);
+    let crate_items = tcx.hir_crate_items(());
 
-    collector.diagnostic_items
+    for id in crate_items.items() {
+        observe_item(tcx, &mut diagnostic_items, id.def_id);
+    }
+
+    for id in crate_items.trait_items() {
+        observe_item(tcx, &mut diagnostic_items, id.def_id);
+    }
+
+    for id in crate_items.impl_items() {
+        observe_item(tcx, &mut diagnostic_items, id.def_id);
+    }
+
+    for id in crate_items.foreign_items() {
+        observe_item(tcx, &mut diagnostic_items, id.def_id);
+    }
+
+    diagnostic_items
 }
 
 /// Traverse and collect all the diagnostic items in all crates.
diff --git a/compiler/rustc_passes/src/entry.rs b/compiler/rustc_passes/src/entry.rs
index f84b848..f9e6731 100644
--- a/compiler/rustc_passes/src/entry.rs
+++ b/compiler/rustc_passes/src/entry.rs
@@ -1,8 +1,8 @@
 use rustc_ast::entry::EntryPointType;
 use rustc_errors::struct_span_err;
+use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE};
-use rustc_hir::itemlikevisit::ItemLikeVisitor;
-use rustc_hir::{ForeignItem, ImplItem, Item, ItemKind, Node, TraitItem, CRATE_HIR_ID};
+use rustc_hir::{ItemId, Node, CRATE_HIR_ID};
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::{DefIdTree, TyCtxt};
 use rustc_session::config::{CrateType, EntryFnType};
@@ -25,25 +25,6 @@
     non_main_fns: Vec<Span>,
 }
 
-impl<'tcx> ItemLikeVisitor<'tcx> for EntryContext<'tcx> {
-    fn visit_item(&mut self, item: &'tcx Item<'tcx>) {
-        let at_root = self.tcx.opt_local_parent(item.def_id) == Some(CRATE_DEF_ID);
-        find_item(item, self, at_root);
-    }
-
-    fn visit_trait_item(&mut self, _trait_item: &'tcx TraitItem<'tcx>) {
-        // Entry fn is never a trait item.
-    }
-
-    fn visit_impl_item(&mut self, _impl_item: &'tcx ImplItem<'tcx>) {
-        // Entry fn is never a trait item.
-    }
-
-    fn visit_foreign_item(&mut self, _: &'tcx ForeignItem<'tcx>) {
-        // Entry fn is never a foreign item.
-    }
-}
-
 fn entry_fn(tcx: TyCtxt<'_>, (): ()) -> Option<(DefId, EntryFnType)> {
     let any_exe = tcx.sess.crate_types().iter().any(|ty| *ty == CrateType::Executable);
     if !any_exe {
@@ -59,28 +40,35 @@
     let mut ctxt =
         EntryContext { tcx, attr_main_fn: None, start_fn: None, non_main_fns: Vec::new() };
 
-    tcx.hir().visit_all_item_likes(&mut ctxt);
+    for id in tcx.hir().items() {
+        find_item(id, &mut ctxt);
+    }
 
     configure_main(tcx, &ctxt)
 }
 
 // Beware, this is duplicated in `librustc_builtin_macros/test_harness.rs`
 // (with `ast::Item`), so make sure to keep them in sync.
-fn entry_point_type(ctxt: &EntryContext<'_>, item: &Item<'_>, at_root: bool) -> EntryPointType {
-    let attrs = ctxt.tcx.hir().attrs(item.hir_id());
+// A small optimization was added so that hir::Item is fetched only when needed.
+// An equivalent optimization was not applied to the duplicated code in test_harness.rs.
+fn entry_point_type(ctxt: &EntryContext<'_>, id: ItemId, at_root: bool) -> EntryPointType {
+    let attrs = ctxt.tcx.hir().attrs(id.hir_id());
     if ctxt.tcx.sess.contains_name(attrs, sym::start) {
         EntryPointType::Start
     } else if ctxt.tcx.sess.contains_name(attrs, sym::rustc_main) {
-        EntryPointType::MainAttr
-    } else if item.ident.name == sym::main {
-        if at_root {
-            // This is a top-level function so can be `main`.
-            EntryPointType::MainNamed
-        } else {
-            EntryPointType::OtherMain
-        }
+        EntryPointType::RustcMainAttr
     } else {
-        EntryPointType::None
+        if let Some(name) = ctxt.tcx.opt_item_name(id.def_id.to_def_id())
+            && name == sym::main {
+            if at_root {
+                // This is a top-level function so can be `main`.
+                EntryPointType::MainNamed
+            } else {
+                EntryPointType::OtherMain
+            }
+        } else {
+            EntryPointType::None
+        }
     }
 }
 
@@ -89,11 +77,13 @@
         .emit();
 }
 
-fn find_item(item: &Item<'_>, ctxt: &mut EntryContext<'_>, at_root: bool) {
-    match entry_point_type(ctxt, item, at_root) {
+fn find_item(id: ItemId, ctxt: &mut EntryContext<'_>) {
+    let at_root = ctxt.tcx.opt_local_parent(id.def_id) == Some(CRATE_DEF_ID);
+
+    match entry_point_type(ctxt, id, at_root) {
         EntryPointType::None => (),
-        _ if !matches!(item.kind, ItemKind::Fn(..)) => {
-            let attrs = ctxt.tcx.hir().attrs(item.hir_id());
+        _ if !matches!(ctxt.tcx.def_kind(id.def_id), DefKind::Fn) => {
+            let attrs = ctxt.tcx.hir().attrs(id.hir_id());
             if let Some(attr) = ctxt.tcx.sess.find_by_name(attrs, sym::start) {
                 throw_attr_err(&ctxt.tcx.sess, attr.span, "start");
             }
@@ -103,31 +93,39 @@
         }
         EntryPointType::MainNamed => (),
         EntryPointType::OtherMain => {
-            ctxt.non_main_fns.push(item.span);
+            ctxt.non_main_fns.push(ctxt.tcx.def_span(id.def_id));
         }
-        EntryPointType::MainAttr => {
+        EntryPointType::RustcMainAttr => {
             if ctxt.attr_main_fn.is_none() {
-                ctxt.attr_main_fn = Some((item.def_id, item.span));
+                ctxt.attr_main_fn = Some((id.def_id, ctxt.tcx.def_span(id.def_id.to_def_id())));
             } else {
                 struct_span_err!(
                     ctxt.tcx.sess,
-                    item.span,
+                    ctxt.tcx.def_span(id.def_id.to_def_id()),
                     E0137,
-                    "multiple functions with a `#[main]` attribute"
+                    "multiple functions with a `#[rustc_main]` attribute"
                 )
-                .span_label(item.span, "additional `#[main]` function")
-                .span_label(ctxt.attr_main_fn.unwrap().1, "first `#[main]` function")
+                .span_label(
+                    ctxt.tcx.def_span(id.def_id.to_def_id()),
+                    "additional `#[rustc_main]` function",
+                )
+                .span_label(ctxt.attr_main_fn.unwrap().1, "first `#[rustc_main]` function")
                 .emit();
             }
         }
         EntryPointType::Start => {
             if ctxt.start_fn.is_none() {
-                ctxt.start_fn = Some((item.def_id, item.span));
+                ctxt.start_fn = Some((id.def_id, ctxt.tcx.def_span(id.def_id.to_def_id())));
             } else {
-                struct_span_err!(ctxt.tcx.sess, item.span, E0138, "multiple `start` functions")
-                    .span_label(ctxt.start_fn.unwrap().1, "previous `#[start]` function here")
-                    .span_label(item.span, "multiple `start` functions")
-                    .emit();
+                struct_span_err!(
+                    ctxt.tcx.sess,
+                    ctxt.tcx.def_span(id.def_id.to_def_id()),
+                    E0138,
+                    "multiple `start` functions"
+                )
+                .span_label(ctxt.start_fn.unwrap().1, "previous `#[start]` function here")
+                .span_label(ctxt.tcx.def_span(id.def_id.to_def_id()), "multiple `start` functions")
+                .emit();
             }
         }
     }
diff --git a/compiler/rustc_passes/src/hir_id_validator.rs b/compiler/rustc_passes/src/hir_id_validator.rs
index 379a682..23ff0a9 100644
--- a/compiler/rustc_passes/src/hir_id_validator.rs
+++ b/compiler/rustc_passes/src/hir_id_validator.rs
@@ -3,7 +3,6 @@
 use rustc_hir as hir;
 use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
 use rustc_hir::intravisit;
-use rustc_hir::itemlikevisit::ItemLikeVisitor;
 use rustc_hir::{HirId, ItemLocalId};
 use rustc_middle::hir::map::Map;
 use rustc_middle::hir::nested_filter;
@@ -20,8 +19,14 @@
     let hir_map = tcx.hir();
 
     hir_map.par_for_each_module(|module_id| {
-        hir_map
-            .visit_item_likes_in_module(module_id, &mut OuterVisitor { hir_map, errors: &errors })
+        let mut v = HirIdValidator {
+            hir_map,
+            owner: None,
+            hir_ids_seen: Default::default(),
+            errors: &errors,
+        };
+
+        tcx.hir().deep_visit_item_likes_in_module(module_id, &mut v);
     });
 
     let errors = errors.into_inner();
@@ -39,13 +44,8 @@
     errors: &'a Lock<Vec<String>>,
 }
 
-struct OuterVisitor<'a, 'hir> {
-    hir_map: Map<'hir>,
-    errors: &'a Lock<Vec<String>>,
-}
-
-impl<'a, 'hir> OuterVisitor<'a, 'hir> {
-    fn new_inner_visitor(&self, hir_map: Map<'hir>) -> HirIdValidator<'a, 'hir> {
+impl<'a, 'hir> HirIdValidator<'a, 'hir> {
+    fn new_visitor(&self, hir_map: Map<'hir>) -> HirIdValidator<'a, 'hir> {
         HirIdValidator {
             hir_map,
             owner: None,
@@ -53,31 +53,7 @@
             errors: self.errors,
         }
     }
-}
 
-impl<'a, 'hir> ItemLikeVisitor<'hir> for OuterVisitor<'a, 'hir> {
-    fn visit_item(&mut self, i: &'hir hir::Item<'hir>) {
-        let mut inner_visitor = self.new_inner_visitor(self.hir_map);
-        inner_visitor.check(i.def_id, |this| intravisit::walk_item(this, i));
-    }
-
-    fn visit_trait_item(&mut self, i: &'hir hir::TraitItem<'hir>) {
-        let mut inner_visitor = self.new_inner_visitor(self.hir_map);
-        inner_visitor.check(i.def_id, |this| intravisit::walk_trait_item(this, i));
-    }
-
-    fn visit_impl_item(&mut self, i: &'hir hir::ImplItem<'hir>) {
-        let mut inner_visitor = self.new_inner_visitor(self.hir_map);
-        inner_visitor.check(i.def_id, |this| intravisit::walk_impl_item(this, i));
-    }
-
-    fn visit_foreign_item(&mut self, i: &'hir hir::ForeignItem<'hir>) {
-        let mut inner_visitor = self.new_inner_visitor(self.hir_map);
-        inner_visitor.check(i.def_id, |this| intravisit::walk_foreign_item(this, i));
-    }
-}
-
-impl<'a, 'hir> HirIdValidator<'a, 'hir> {
     #[cold]
     #[inline(never)]
     fn error(&self, f: impl FnOnce() -> String) {
@@ -146,6 +122,11 @@
         self.hir_map
     }
 
+    fn visit_item(&mut self, i: &'hir hir::Item<'hir>) {
+        let mut inner_visitor = self.new_visitor(self.hir_map);
+        inner_visitor.check(i.def_id, |this| intravisit::walk_item(this, i));
+    }
+
     fn visit_id(&mut self, hir_id: HirId) {
         let owner = self.owner.expect("no owner");
 
@@ -163,17 +144,18 @@
         self.hir_ids_seen.insert(hir_id.local_id);
     }
 
-    fn visit_impl_item_ref(&mut self, _: &'hir hir::ImplItemRef) {
-        // Explicitly do nothing here. ImplItemRefs contain hir::Visibility
-        // values that actually belong to an ImplItem instead of the ItemKind::Impl
-        // we are currently in. So for those it's correct that they have a
-        // different owner.
+    fn visit_foreign_item(&mut self, i: &'hir hir::ForeignItem<'hir>) {
+        let mut inner_visitor = self.new_visitor(self.hir_map);
+        inner_visitor.check(i.def_id, |this| intravisit::walk_foreign_item(this, i));
     }
 
-    fn visit_foreign_item_ref(&mut self, _: &'hir hir::ForeignItemRef) {
-        // Explicitly do nothing here. ForeignItemRefs contain hir::Visibility
-        // values that actually belong to an ForeignItem instead of the ItemKind::ForeignMod
-        // we are currently in. So for those it's correct that they have a
-        // different owner.
+    fn visit_trait_item(&mut self, i: &'hir hir::TraitItem<'hir>) {
+        let mut inner_visitor = self.new_visitor(self.hir_map);
+        inner_visitor.check(i.def_id, |this| intravisit::walk_trait_item(this, i));
+    }
+
+    fn visit_impl_item(&mut self, i: &'hir hir::ImplItem<'hir>) {
+        let mut inner_visitor = self.new_visitor(self.hir_map);
+        inner_visitor.check(i.def_id, |this| intravisit::walk_impl_item(this, i));
     }
 }
diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs
index 237a8ab..a3be827 100644
--- a/compiler/rustc_passes/src/hir_stats.rs
+++ b/compiler/rustc_passes/src/hir_stats.rs
@@ -238,7 +238,7 @@
         hir_visit::walk_assoc_type_binding(self, type_binding)
     }
 
-    fn visit_attribute(&mut self, _: hir::HirId, attr: &'v ast::Attribute) {
+    fn visit_attribute(&mut self, attr: &'v ast::Attribute) {
         self.record("Attribute", Id::Attr(attr.id), attr);
     }
 }
@@ -318,7 +318,7 @@
         ast_visit::walk_variant(self, v)
     }
 
-    fn visit_lifetime(&mut self, lifetime: &'v ast::Lifetime) {
+    fn visit_lifetime(&mut self, lifetime: &'v ast::Lifetime, _: ast_visit::LifetimeCtxt) {
         self.record("Lifetime", Id::None, lifetime);
         ast_visit::walk_lifetime(self, lifetime)
     }
diff --git a/compiler/rustc_passes/src/layout_test.rs b/compiler/rustc_passes/src/layout_test.rs
index 728aaab..fd03f65 100644
--- a/compiler/rustc_passes/src/layout_test.rs
+++ b/compiler/rustc_passes/src/layout_test.rs
@@ -1,8 +1,6 @@
 use rustc_ast::Attribute;
-use rustc_hir as hir;
+use rustc_hir::def::DefKind;
 use rustc_hir::def_id::LocalDefId;
-use rustc_hir::itemlikevisit::ItemLikeVisitor;
-use rustc_hir::ItemKind;
 use rustc_middle::ty::layout::{HasParamEnv, HasTyCtxt, LayoutError, LayoutOfHelpers, TyAndLayout};
 use rustc_middle::ty::{ParamEnv, Ty, TyCtxt};
 use rustc_span::symbol::sym;
@@ -12,97 +10,87 @@
 pub fn test_layout(tcx: TyCtxt<'_>) {
     if tcx.features().rustc_attrs {
         // if the `rustc_attrs` feature is not enabled, don't bother testing layout
-        tcx.hir().visit_all_item_likes(&mut LayoutTest { tcx });
-    }
-}
-
-struct LayoutTest<'tcx> {
-    tcx: TyCtxt<'tcx>,
-}
-
-impl<'tcx> ItemLikeVisitor<'tcx> for LayoutTest<'tcx> {
-    fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
-        match item.kind {
-            ItemKind::TyAlias(..)
-            | ItemKind::Enum(..)
-            | ItemKind::Struct(..)
-            | ItemKind::Union(..) => {
-                for attr in self.tcx.get_attrs(item.def_id.to_def_id(), sym::rustc_layout) {
-                    self.dump_layout_of(item.def_id, item, attr);
+        for id in tcx.hir().items() {
+            if matches!(
+                tcx.def_kind(id.def_id),
+                DefKind::TyAlias | DefKind::Enum | DefKind::Struct | DefKind::Union
+            ) {
+                for attr in tcx.get_attrs(id.def_id.to_def_id(), sym::rustc_layout) {
+                    dump_layout_of(tcx, id.def_id, attr);
                 }
             }
-            _ => {}
         }
     }
-
-    fn visit_trait_item(&mut self, _: &'tcx hir::TraitItem<'tcx>) {}
-    fn visit_impl_item(&mut self, _: &'tcx hir::ImplItem<'tcx>) {}
-    fn visit_foreign_item(&mut self, _: &'tcx hir::ForeignItem<'tcx>) {}
 }
 
-impl<'tcx> LayoutTest<'tcx> {
-    fn dump_layout_of(&self, item_def_id: LocalDefId, item: &hir::Item<'tcx>, attr: &Attribute) {
-        let tcx = self.tcx;
-        let param_env = self.tcx.param_env(item_def_id);
-        let ty = self.tcx.type_of(item_def_id);
-        match self.tcx.layout_of(param_env.and(ty)) {
-            Ok(ty_layout) => {
-                // Check out the `#[rustc_layout(..)]` attribute to tell what to dump.
-                // The `..` are the names of fields to dump.
-                let meta_items = attr.meta_item_list().unwrap_or_default();
-                for meta_item in meta_items {
-                    match meta_item.name_or_empty() {
-                        sym::abi => {
-                            self.tcx.sess.span_err(item.span, &format!("abi: {:?}", ty_layout.abi));
-                        }
+fn dump_layout_of<'tcx>(tcx: TyCtxt<'tcx>, item_def_id: LocalDefId, attr: &Attribute) {
+    let tcx = tcx;
+    let param_env = tcx.param_env(item_def_id);
+    let ty = tcx.type_of(item_def_id);
+    match tcx.layout_of(param_env.and(ty)) {
+        Ok(ty_layout) => {
+            // Check out the `#[rustc_layout(..)]` attribute to tell what to dump.
+            // The `..` are the names of fields to dump.
+            let meta_items = attr.meta_item_list().unwrap_or_default();
+            for meta_item in meta_items {
+                match meta_item.name_or_empty() {
+                    sym::abi => {
+                        tcx.sess.span_err(
+                            tcx.def_span(item_def_id.to_def_id()),
+                            &format!("abi: {:?}", ty_layout.abi),
+                        );
+                    }
 
-                        sym::align => {
-                            self.tcx
-                                .sess
-                                .span_err(item.span, &format!("align: {:?}", ty_layout.align));
-                        }
+                    sym::align => {
+                        tcx.sess.span_err(
+                            tcx.def_span(item_def_id.to_def_id()),
+                            &format!("align: {:?}", ty_layout.align),
+                        );
+                    }
 
-                        sym::size => {
-                            self.tcx
-                                .sess
-                                .span_err(item.span, &format!("size: {:?}", ty_layout.size));
-                        }
+                    sym::size => {
+                        tcx.sess.span_err(
+                            tcx.def_span(item_def_id.to_def_id()),
+                            &format!("size: {:?}", ty_layout.size),
+                        );
+                    }
 
-                        sym::homogeneous_aggregate => {
-                            self.tcx.sess.span_err(
-                                item.span,
-                                &format!(
-                                    "homogeneous_aggregate: {:?}",
-                                    ty_layout
-                                        .homogeneous_aggregate(&UnwrapLayoutCx { tcx, param_env }),
-                                ),
-                            );
-                        }
+                    sym::homogeneous_aggregate => {
+                        tcx.sess.span_err(
+                            tcx.def_span(item_def_id.to_def_id()),
+                            &format!(
+                                "homogeneous_aggregate: {:?}",
+                                ty_layout.homogeneous_aggregate(&UnwrapLayoutCx { tcx, param_env }),
+                            ),
+                        );
+                    }
 
-                        sym::debug => {
-                            let normalized_ty = self.tcx.normalize_erasing_regions(
-                                param_env.with_reveal_all_normalized(self.tcx),
-                                ty,
-                            );
-                            self.tcx.sess.span_err(
-                                item.span,
-                                &format!("layout_of({:?}) = {:#?}", normalized_ty, *ty_layout),
-                            );
-                        }
+                    sym::debug => {
+                        let normalized_ty = tcx.normalize_erasing_regions(
+                            param_env.with_reveal_all_normalized(tcx),
+                            ty,
+                        );
+                        tcx.sess.span_err(
+                            tcx.def_span(item_def_id.to_def_id()),
+                            &format!("layout_of({:?}) = {:#?}", normalized_ty, *ty_layout),
+                        );
+                    }
 
-                        name => {
-                            self.tcx.sess.span_err(
-                                meta_item.span(),
-                                &format!("unrecognized field name `{}`", name),
-                            );
-                        }
+                    name => {
+                        tcx.sess.span_err(
+                            meta_item.span(),
+                            &format!("unrecognized field name `{}`", name),
+                        );
                     }
                 }
             }
+        }
 
-            Err(layout_error) => {
-                self.tcx.sess.span_err(item.span, &format!("layout error: {:?}", layout_error));
-            }
+        Err(layout_error) => {
+            tcx.sess.span_err(
+                tcx.def_span(item_def_id.to_def_id()),
+                &format!("layout error: {:?}", layout_error),
+            );
         }
     }
 }
diff --git a/compiler/rustc_passes/src/lib.rs b/compiler/rustc_passes/src/lib.rs
index d9d0848..497c093 100644
--- a/compiler/rustc_passes/src/lib.rs
+++ b/compiler/rustc_passes/src/lib.rs
@@ -6,13 +6,11 @@
 
 #![allow(rustc::potential_query_instability)]
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
-#![feature(crate_visibility_modifier)]
 #![feature(iter_intersperse)]
 #![feature(let_else)]
 #![feature(let_chains)]
 #![feature(map_try_insert)]
 #![feature(min_specialization)]
-#![feature(nll)]
 #![feature(try_blocks)]
 #![recursion_limit = "256"]
 
@@ -31,7 +29,6 @@
 pub mod entry;
 pub mod hir_id_validator;
 pub mod hir_stats;
-mod intrinsicck;
 mod lang_items;
 pub mod layout_test;
 mod lib_features;
@@ -39,7 +36,6 @@
 pub mod loops;
 mod naked_functions;
 mod reachable;
-mod region;
 pub mod stability;
 mod upvars;
 mod weak_lang_items;
@@ -56,9 +52,7 @@
     loops::provide(providers);
     naked_functions::provide(providers);
     liveness::provide(providers);
-    intrinsicck::provide(providers);
     reachable::provide(providers);
-    region::provide(providers);
     stability::provide(providers);
     upvars::provide(providers);
 }
diff --git a/compiler/rustc_passes/src/lib_features.rs b/compiler/rustc_passes/src/lib_features.rs
index c414d7c..26bfa47 100644
--- a/compiler/rustc_passes/src/lib_features.rs
+++ b/compiler/rustc_passes/src/lib_features.rs
@@ -120,7 +120,7 @@
         self.tcx.hir()
     }
 
-    fn visit_attribute(&mut self, _: rustc_hir::HirId, attr: &'tcx Attribute) {
+    fn visit_attribute(&mut self, attr: &'tcx Attribute) {
         if let Some((feature, stable, span)) = self.extract(attr) {
             self.collect_feature(feature, stable, span);
         }
diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs
index 9eba7fb..80a263f 100644
--- a/compiler/rustc_passes/src/liveness.rs
+++ b/compiler/rustc_passes/src/liveness.rs
@@ -140,7 +140,7 @@
 }
 
 fn check_mod_liveness(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
-    tcx.hir().visit_item_likes_in_module(module_def_id, &mut IrMaps::new(tcx).as_deep_visitor());
+    tcx.hir().deep_visit_item_likes_in_module(module_def_id, &mut IrMaps::new(tcx));
 }
 
 pub fn provide(providers: &mut Providers) {
@@ -373,8 +373,8 @@
 
     fn visit_arm(&mut self, arm: &'tcx hir::Arm<'tcx>) {
         self.add_from_pat(&arm.pat);
-        if let Some(hir::Guard::IfLet(ref pat, _)) = arm.guard {
-            self.add_from_pat(pat);
+        if let Some(hir::Guard::IfLet(ref let_expr)) = arm.guard {
+            self.add_from_pat(let_expr.pat);
         }
         intravisit::walk_arm(self, arm);
     }
@@ -405,7 +405,7 @@
                 }
                 intravisit::walk_expr(self, expr);
             }
-            hir::ExprKind::Closure(..) => {
+            hir::ExprKind::Closure { .. } => {
                 // Interesting control flow (for loops can contain labeled
                 // breaks or continues)
                 self.add_live_node_for_node(expr.hir_id, ExprNode(expr.span, expr.hir_id));
@@ -833,7 +833,7 @@
 
             hir::ExprKind::Field(ref e, _) => self.propagate_through_expr(&e, succ),
 
-            hir::ExprKind::Closure(..) => {
+            hir::ExprKind::Closure { .. } => {
                 debug!("{:?} is an ExprKind::Closure", expr);
 
                 // the construction of a closure itself is not important,
@@ -914,9 +914,9 @@
 
                     let guard_succ = arm.guard.as_ref().map_or(body_succ, |g| match g {
                         hir::Guard::If(e) => self.propagate_through_expr(e, body_succ),
-                        hir::Guard::IfLet(pat, e) => {
-                            let let_bind = self.define_bindings_in_pat(pat, body_succ);
-                            self.propagate_through_expr(e, let_bind)
+                        hir::Guard::IfLet(let_expr) => {
+                            let let_bind = self.define_bindings_in_pat(let_expr.pat, body_succ);
+                            self.propagate_through_expr(let_expr.init, let_bind)
                         }
                     });
                     let arm_succ = self.define_bindings_in_pat(&arm.pat, guard_succ);
@@ -1387,7 +1387,7 @@
         | hir::ExprKind::AddrOf(..)
         | hir::ExprKind::Struct(..)
         | hir::ExprKind::Repeat(..)
-        | hir::ExprKind::Closure(..)
+        | hir::ExprKind::Closure { .. }
         | hir::ExprKind::Path(_)
         | hir::ExprKind::Yield(..)
         | hir::ExprKind::Box(..)
diff --git a/compiler/rustc_passes/src/loops.rs b/compiler/rustc_passes/src/loops.rs
index 02b09da..9cfef26 100644
--- a/compiler/rustc_passes/src/loops.rs
+++ b/compiler/rustc_passes/src/loops.rs
@@ -31,9 +31,9 @@
 }
 
 fn check_mod_loops(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
-    tcx.hir().visit_item_likes_in_module(
+    tcx.hir().deep_visit_item_likes_in_module(
         module_def_id,
-        &mut CheckLoopVisitor { sess: &tcx.sess, hir_map: tcx.hir(), cx: Normal }.as_deep_visitor(),
+        &mut CheckLoopVisitor { sess: &tcx.sess, hir_map: tcx.hir(), cx: Normal },
     );
 }
 
@@ -57,14 +57,14 @@
             hir::ExprKind::Loop(ref b, _, source, _) => {
                 self.with_context(Loop(source), |v| v.visit_block(&b));
             }
-            hir::ExprKind::Closure(_, ref function_decl, b, span, movability) => {
+            hir::ExprKind::Closure { ref fn_decl, body, fn_decl_span, movability, .. } => {
                 let cx = if let Some(Movability::Static) = movability {
-                    AsyncClosure(span)
+                    AsyncClosure(fn_decl_span)
                 } else {
-                    Closure(span)
+                    Closure(fn_decl_span)
                 };
-                self.visit_fn_decl(&function_decl);
-                self.with_context(cx, |v| v.visit_nested_body(b));
+                self.visit_fn_decl(&fn_decl);
+                self.with_context(cx, |v| v.visit_nested_body(body));
             }
             hir::ExprKind::Block(ref b, Some(_label)) => {
                 self.with_context(LabeledBlock, |v| v.visit_block(&b));
@@ -166,7 +166,7 @@
                                             break_expr.span,
                                             "alternatively, you might have meant to use the \
                                              available loop label",
-                                            label.ident.to_string(),
+                                            label.ident,
                                             Applicability::MaybeIncorrect,
                                         );
                                     }
diff --git a/compiler/rustc_passes/src/naked_functions.rs b/compiler/rustc_passes/src/naked_functions.rs
index e857209..40844b8 100644
--- a/compiler/rustc_passes/src/naked_functions.rs
+++ b/compiler/rustc_passes/src/naked_functions.rs
@@ -14,13 +14,10 @@
 use rustc_target::spec::abi::Abi;
 
 fn check_mod_naked_functions(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
-    tcx.hir().visit_item_likes_in_module(
-        module_def_id,
-        &mut CheckNakedFunctions { tcx }.as_deep_visitor(),
-    );
+    tcx.hir().deep_visit_item_likes_in_module(module_def_id, &mut CheckNakedFunctions { tcx });
 }
 
-crate fn provide(providers: &mut Providers) {
+pub(crate) fn provide(providers: &mut Providers) {
     *providers = Providers { check_mod_naked_functions, ..*providers };
 }
 
@@ -215,7 +212,7 @@
             | ExprKind::Loop(..)
             | ExprKind::Match(..)
             | ExprKind::If(..)
-            | ExprKind::Closure(..)
+            | ExprKind::Closure { .. }
             | ExprKind::Assign(..)
             | ExprKind::AssignOp(..)
             | ExprKind::Field(..)
@@ -311,7 +308,7 @@
                 last_span,
                 "consider specifying that the asm block is responsible \
                 for returning from the function",
-                String::from(", options(noreturn)"),
+                ", options(noreturn)",
                 Applicability::MachineApplicable,
             )
             .emit();
diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs
index a5133bf..c830ab1 100644
--- a/compiler/rustc_passes/src/reachable.rs
+++ b/compiler/rustc_passes/src/reachable.rs
@@ -10,7 +10,6 @@
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::intravisit::{self, Visitor};
-use rustc_hir::itemlikevisit::ItemLikeVisitor;
 use rustc_hir::Node;
 use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
 use rustc_middle::middle::privacy;
@@ -149,32 +148,15 @@
                 hir::TraitItemKind::Fn(_, hir::TraitFn::Required(_))
                 | hir::TraitItemKind::Type(..) => false,
             },
-            Some(Node::ImplItem(impl_item)) => {
-                match impl_item.kind {
-                    hir::ImplItemKind::Const(..) => true,
-                    hir::ImplItemKind::Fn(..) => {
-                        let attrs = self.tcx.codegen_fn_attrs(def_id);
-                        let generics = self.tcx.generics_of(def_id);
-                        if generics.requires_monomorphization(self.tcx) || attrs.requests_inline() {
-                            true
-                        } else {
-                            let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
-                            let impl_did = self.tcx.hir().get_parent_item(hir_id);
-                            // Check the impl. If the generics on the self
-                            // type of the impl require inlining, this method
-                            // does too.
-                            match self.tcx.hir().expect_item(impl_did).kind {
-                                hir::ItemKind::Impl { .. } => {
-                                    let generics = self.tcx.generics_of(impl_did);
-                                    generics.requires_monomorphization(self.tcx)
-                                }
-                                _ => false,
-                            }
-                        }
-                    }
-                    hir::ImplItemKind::TyAlias(_) => false,
+            Some(Node::ImplItem(impl_item)) => match impl_item.kind {
+                hir::ImplItemKind::Const(..) => true,
+                hir::ImplItemKind::Fn(..) => {
+                    let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
+                    let impl_did = self.tcx.hir().get_parent_item(hir_id);
+                    method_might_be_inlined(self.tcx, impl_item, impl_did)
                 }
-            }
+                hir::ImplItemKind::TyAlias(_) => false,
+            },
             Some(_) => false,
             None => false, // This will happen for default methods.
         }
@@ -291,7 +273,7 @@
                 }
                 hir::ImplItemKind::TyAlias(_) => {}
             },
-            Node::Expr(&hir::Expr { kind: hir::ExprKind::Closure(.., body, _, _), .. }) => {
+            Node::Expr(&hir::Expr { kind: hir::ExprKind::Closure { body, .. }, .. }) => {
                 self.visit_nested_body(body);
             }
             // Nothing to recurse on for these
@@ -314,79 +296,58 @@
     }
 }
 
-// Some methods from non-exported (completely private) trait impls still have to be
-// reachable if they are called from inlinable code. Generally, it's not known until
-// monomorphization if a specific trait impl item can be reachable or not. So, we
-// conservatively mark all of them as reachable.
-// FIXME: One possible strategy for pruning the reachable set is to avoid marking impl
-// items of non-exported traits (or maybe all local traits?) unless their respective
-// trait items are used from inlinable code through method call syntax or UFCS, or their
-// trait is a lang item.
-struct CollectPrivateImplItemsVisitor<'a, 'tcx> {
+fn check_item<'tcx>(
     tcx: TyCtxt<'tcx>,
-    access_levels: &'a privacy::AccessLevels,
-    worklist: &'a mut Vec<LocalDefId>,
-}
+    id: hir::ItemId,
+    worklist: &mut Vec<LocalDefId>,
+    access_levels: &privacy::AccessLevels,
+) {
+    if has_custom_linkage(tcx, id.def_id) {
+        worklist.push(id.def_id);
+    }
 
-impl CollectPrivateImplItemsVisitor<'_, '_> {
-    fn push_to_worklist_if_has_custom_linkage(&mut self, def_id: LocalDefId) {
-        // Anything which has custom linkage gets thrown on the worklist no
-        // matter where it is in the crate, along with "special std symbols"
-        // which are currently akin to allocator symbols.
-        if self.tcx.def_kind(def_id).has_codegen_attrs() {
-            let codegen_attrs = self.tcx.codegen_fn_attrs(def_id);
-            if codegen_attrs.contains_extern_indicator()
-                || codegen_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL)
-                // FIXME(nbdd0121): `#[used]` are marked as reachable here so it's picked up by
-                // `linked_symbols` in cg_ssa. They won't be exported in binary or cdylib due to their
-                // `SymbolExportLevel::Rust` export level but may end up being exported in dylibs.
-                || codegen_attrs.flags.contains(CodegenFnAttrFlags::USED)
-                || codegen_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER)
-            {
-                self.worklist.push(def_id);
+    if !matches!(tcx.def_kind(id.def_id), DefKind::Impl) {
+        return;
+    }
+
+    // We need only trait impls here, not inherent impls, and only non-exported ones
+    let item = tcx.hir().item(id);
+    if let hir::ItemKind::Impl(hir::Impl { of_trait: Some(ref trait_ref), ref items, .. }) =
+        item.kind
+    {
+        if !access_levels.is_reachable(item.def_id) {
+            worklist.extend(items.iter().map(|ii_ref| ii_ref.id.def_id));
+
+            let Res::Def(DefKind::Trait, trait_def_id) = trait_ref.path.res else {
+                unreachable!();
+            };
+
+            if !trait_def_id.is_local() {
+                return;
             }
+
+            worklist.extend(
+                tcx.provided_trait_methods(trait_def_id).map(|assoc| assoc.def_id.expect_local()),
+            );
         }
     }
 }
 
-impl<'a, 'tcx> ItemLikeVisitor<'tcx> for CollectPrivateImplItemsVisitor<'a, 'tcx> {
-    fn visit_item(&mut self, item: &hir::Item<'_>) {
-        self.push_to_worklist_if_has_custom_linkage(item.def_id);
-
-        // We need only trait impls here, not inherent impls, and only non-exported ones
-        if let hir::ItemKind::Impl(hir::Impl { of_trait: Some(ref trait_ref), ref items, .. }) =
-            item.kind
-        {
-            if !self.access_levels.is_reachable(item.def_id) {
-                // FIXME(#53488) remove `let`
-                let tcx = self.tcx;
-                self.worklist.extend(items.iter().map(|ii_ref| ii_ref.id.def_id));
-
-                let Res::Def(DefKind::Trait, trait_def_id) = trait_ref.path.res else {
-                    unreachable!();
-                };
-
-                if !trait_def_id.is_local() {
-                    return;
-                }
-
-                self.worklist.extend(
-                    tcx.provided_trait_methods(trait_def_id)
-                        .map(|assoc| assoc.def_id.expect_local()),
-                );
-            }
-        }
+fn has_custom_linkage<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> bool {
+    // Anything which has custom linkage gets thrown on the worklist no
+    // matter where it is in the crate, along with "special std symbols"
+    // which are currently akin to allocator symbols.
+    if !tcx.def_kind(def_id).has_codegen_attrs() {
+        return false;
     }
-
-    fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem<'_>) {}
-
-    fn visit_impl_item(&mut self, impl_item: &hir::ImplItem<'_>) {
-        self.push_to_worklist_if_has_custom_linkage(impl_item.def_id);
-    }
-
-    fn visit_foreign_item(&mut self, _foreign_item: &hir::ForeignItem<'_>) {
-        // We never export foreign functions as they have no body to export.
-    }
+    let codegen_attrs = tcx.codegen_fn_attrs(def_id);
+    codegen_attrs.contains_extern_indicator()
+        || codegen_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL)
+        // FIXME(nbdd0121): `#[used]` are marked as reachable here so it's picked up by
+        // `linked_symbols` in cg_ssa. They won't be exported in binary or cdylib due to their
+        // `SymbolExportLevel::Rust` export level but may end up being exported in dylibs.
+        || codegen_attrs.flags.contains(CodegenFnAttrFlags::USED)
+        || codegen_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER)
 }
 
 fn reachable_set<'tcx>(tcx: TyCtxt<'tcx>, (): ()) -> FxHashSet<LocalDefId> {
@@ -418,12 +379,25 @@
         }
     }
     {
-        let mut collect_private_impl_items = CollectPrivateImplItemsVisitor {
-            tcx,
-            access_levels,
-            worklist: &mut reachable_context.worklist,
-        };
-        tcx.hir().visit_all_item_likes(&mut collect_private_impl_items);
+        // Some methods from non-exported (completely private) trait impls still have to be
+        // reachable if they are called from inlinable code. Generally, it's not known until
+        // monomorphization if a specific trait impl item can be reachable or not. So, we
+        // conservatively mark all of them as reachable.
+        // FIXME: One possible strategy for pruning the reachable set is to avoid marking impl
+        // items of non-exported traits (or maybe all local traits?) unless their respective
+        // trait items are used from inlinable code through method call syntax or UFCS, or their
+        // trait is a lang item.
+        let crate_items = tcx.hir_crate_items(());
+
+        for id in crate_items.items() {
+            check_item(tcx, id, &mut reachable_context.worklist, access_levels);
+        }
+
+        for id in crate_items.impl_items() {
+            if has_custom_linkage(tcx, id.def_id) {
+                reachable_context.worklist.push(id.def_id);
+            }
+        }
     }
 
     // Step 2: Mark all symbols that the symbols on the worklist touch.
diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs
index e1bc248..9eaefc8 100644
--- a/compiler/rustc_passes/src/stability.rs
+++ b/compiler/rustc_passes/src/stability.rs
@@ -9,10 +9,10 @@
 use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
 use rustc_hir::hir_id::CRATE_HIR_ID;
 use rustc_hir::intravisit::{self, Visitor};
-use rustc_hir::{FieldDef, Generics, HirId, Item, TraitRef, Ty, TyKind, Variant};
+use rustc_hir::{FieldDef, Generics, HirId, Item, ItemKind, TraitRef, Ty, TyKind, Variant};
 use rustc_middle::hir::nested_filter;
 use rustc_middle::middle::privacy::AccessLevels;
-use rustc_middle::middle::stability::{DeprecationEntry, Index};
+use rustc_middle::middle::stability::{AllowUnstable, DeprecationEntry, Index};
 use rustc_middle::ty::{self, query::Providers, TyCtxt};
 use rustc_session::lint;
 use rustc_session::lint::builtin::{INEFFECTIVE_UNSTABLE_TRAIT_IMPL, USELESS_DEPRECATED};
@@ -125,7 +125,7 @@
                         .span_suggestion_short(
                             *span,
                             "remove the unnecessary deprecation attribute",
-                            String::new(),
+                            "",
                             rustc_errors::Applicability::MachineApplicable,
                         )
                         .emit();
@@ -147,7 +147,7 @@
             // Propagate unstability.  This can happen even for non-staged-api crates in case
             // -Zforce-unstable-if-unmarked is set.
             if let Some(stab) = self.parent_stab {
-                if inherit_deprecation.yes() && stab.level.is_unstable() {
+                if inherit_deprecation.yes() && stab.is_unstable() {
                     self.index.stab_map.insert(def_id, stab);
                 }
             }
@@ -190,7 +190,7 @@
         if const_stab.is_none() {
             debug!("annotate: const_stab not found, parent = {:?}", self.parent_const_stab);
             if let Some(parent) = self.parent_const_stab {
-                if parent.level.is_unstable() {
+                if parent.is_const_unstable() {
                     self.index.const_stab_map.insert(def_id, parent);
                 }
             }
@@ -272,9 +272,7 @@
         if stab.is_none() {
             debug!("annotate: stab not found, parent = {:?}", self.parent_stab);
             if let Some(stab) = self.parent_stab {
-                if inherit_deprecation.yes() && stab.level.is_unstable()
-                    || inherit_from_parent.yes()
-                {
+                if inherit_deprecation.yes() && stab.is_unstable() || inherit_from_parent.yes() {
                     self.index.stab_map.insert(def_id, stab);
                 }
             }
@@ -532,7 +530,8 @@
             return;
         }
 
-        let is_const = self.tcx.is_const_fn(def_id.to_def_id());
+        let is_const = self.tcx.is_const_fn(def_id.to_def_id())
+            || self.tcx.is_const_trait_impl_raw(def_id.to_def_id());
         let is_stable = self
             .tcx
             .lookup_stability(def_id)
@@ -661,7 +660,7 @@
 /// Cross-references the feature names of unstable APIs with enabled
 /// features and possibly prints errors.
 fn check_mod_unstable_api_usage(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
-    tcx.hir().visit_item_likes_in_module(module_def_id, &mut Checker { tcx }.as_deep_visitor());
+    tcx.hir().deep_visit_item_likes_in_module(module_def_id, &mut Checker { tcx });
 }
 
 pub(crate) fn provide(providers: &mut Providers) {
@@ -710,16 +709,23 @@
             // For implementations of traits, check the stability of each item
             // individually as it's possible to have a stable trait with unstable
             // items.
-            hir::ItemKind::Impl(hir::Impl { of_trait: Some(ref t), self_ty, items, .. }) => {
-                if self.tcx.features().staged_api {
+            hir::ItemKind::Impl(hir::Impl {
+                of_trait: Some(ref t),
+                self_ty,
+                items,
+                constness,
+                ..
+            }) => {
+                let features = self.tcx.features();
+                if features.staged_api {
+                    let attrs = self.tcx.hir().attrs(item.hir_id());
+                    let (stab, const_stab) = attr::find_stability(&self.tcx.sess, attrs, item.span);
+
                     // If this impl block has an #[unstable] attribute, give an
                     // error if all involved types and traits are stable, because
                     // it will have no effect.
                     // See: https://github.com/rust-lang/rust/issues/55436
-                    let attrs = self.tcx.hir().attrs(item.hir_id());
-                    if let (Some((Stability { level: attr::Unstable { .. }, .. }, span)), _) =
-                        attr::find_stability(&self.tcx.sess, attrs, item.span)
-                    {
+                    if let Some((Stability { level: attr::Unstable { .. }, .. }, span)) = stab {
                         let mut c = CheckTraitImplStable { tcx: self.tcx, fully_stable: true };
                         c.visit_ty(self_ty);
                         c.visit_trait_ref(t);
@@ -735,6 +741,19 @@
                             );
                         }
                     }
+
+                    // `#![feature(const_trait_impl)]` is unstable, so any impl declared stable
+                    // needs to have an error emitted.
+                    if features.const_trait_impl
+                        && *constness == hir::Constness::Const
+                        && const_stab.map_or(false, |(stab, _)| stab.is_const_stable())
+                    {
+                        self.tcx
+                            .sess
+                            .struct_span_err(item.span, "trait implementations cannot be const stable yet")
+                            .note("see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information")
+                            .emit();
+                    }
                 }
 
                 for impl_item_ref in *items {
@@ -788,12 +807,46 @@
     fn visit_path(&mut self, path: &'tcx hir::Path<'tcx>, id: hir::HirId) {
         if let Some(def_id) = path.res.opt_def_id() {
             let method_span = path.segments.last().map(|s| s.ident.span);
-            self.tcx.check_stability(def_id, Some(id), path.span, method_span)
+            self.tcx.check_stability_allow_unstable(
+                def_id,
+                Some(id),
+                path.span,
+                method_span,
+                if is_unstable_reexport(self.tcx, id) {
+                    AllowUnstable::Yes
+                } else {
+                    AllowUnstable::No
+                },
+            )
         }
         intravisit::walk_path(self, path)
     }
 }
 
+/// Check whether a path is a `use` item that has been marked as unstable.
+///
+/// See issue #94972 for details on why this is a special case
+fn is_unstable_reexport<'tcx>(tcx: TyCtxt<'tcx>, id: hir::HirId) -> bool {
+    // Get the LocalDefId so we can lookup the item to check the kind.
+    let Some(def_id) = tcx.hir().opt_local_def_id(id) else { return false; };
+
+    let Some(stab) = tcx.stability().local_stability(def_id) else {
+        return false;
+    };
+
+    if stab.level.is_stable() {
+        // The re-export is not marked as unstable, don't override
+        return false;
+    }
+
+    // If this is a path that isn't a use, we don't need to do anything special
+    if !matches!(tcx.hir().item(hir::ItemId { def_id }).kind, ItemKind::Use(..)) {
+        return false;
+    }
+
+    true
+}
+
 struct CheckTraitImplStable<'tcx> {
     tcx: TyCtxt<'tcx>,
     fully_stable: bool,
@@ -837,7 +890,7 @@
         let mut missing = MissingStabilityAnnotations { tcx, access_levels };
         missing.check_missing_stability(CRATE_DEF_ID, tcx.hir().span(CRATE_HIR_ID));
         tcx.hir().walk_toplevel_module(&mut missing);
-        tcx.hir().visit_all_item_likes(&mut missing.as_deep_visitor());
+        tcx.hir().deep_visit_all_item_likes(&mut missing);
     }
 
     let declared_lang_features = &tcx.features().declared_lang_features;
diff --git a/compiler/rustc_passes/src/upvars.rs b/compiler/rustc_passes/src/upvars.rs
index 25fe8e4..97a4612 100644
--- a/compiler/rustc_passes/src/upvars.rs
+++ b/compiler/rustc_passes/src/upvars.rs
@@ -75,7 +75,7 @@
     }
 
     fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
-        if let hir::ExprKind::Closure(..) = expr.kind {
+        if let hir::ExprKind::Closure { .. } = expr.kind {
             let closure_def_id = self.tcx.hir().local_def_id(expr.hir_id);
             if let Some(upvars) = self.tcx.upvars_mentioned(closure_def_id) {
                 // Every capture of a closure expression is a local in scope,
diff --git a/compiler/rustc_passes/src/weak_lang_items.rs b/compiler/rustc_passes/src/weak_lang_items.rs
index 5411946..3291be0 100644
--- a/compiler/rustc_passes/src/weak_lang_items.rs
+++ b/compiler/rustc_passes/src/weak_lang_items.rs
@@ -17,7 +17,7 @@
     if items.eh_personality().is_none() {
         items.missing.push(LangItem::EhPersonality);
     }
-    if tcx.sess.target.is_like_emscripten && items.eh_catch_typeinfo().is_none() {
+    if tcx.sess.target.os == "emscripten" && items.eh_catch_typeinfo().is_none() {
         items.missing.push(LangItem::EhCatchTypeinfo);
     }
 
diff --git a/compiler/rustc_plugin_impl/Cargo.toml b/compiler/rustc_plugin_impl/Cargo.toml
index f5071eb..b6ea533 100644
--- a/compiler/rustc_plugin_impl/Cargo.toml
+++ b/compiler/rustc_plugin_impl/Cargo.toml
@@ -9,9 +9,7 @@
 
 [dependencies]
 libloading = "0.7.1"
-rustc_middle = { path = "../rustc_middle" }
 rustc_errors = { path = "../rustc_errors" }
-rustc_hir = { path = "../rustc_hir" }
 rustc_lint = { path = "../rustc_lint" }
 rustc_metadata = { path = "../rustc_metadata" }
 rustc_ast = { path = "../rustc_ast" }
diff --git a/compiler/rustc_plugin_impl/src/lib.rs b/compiler/rustc_plugin_impl/src/lib.rs
index a1e13a1..1195045 100644
--- a/compiler/rustc_plugin_impl/src/lib.rs
+++ b/compiler/rustc_plugin_impl/src/lib.rs
@@ -7,7 +7,6 @@
 //! of the Unstable Book for some examples.
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
-#![feature(nll)]
 #![recursion_limit = "256"]
 
 use rustc_lint::LintStore;
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index ee459d9..b27c986 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -1,5 +1,4 @@
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
-#![feature(nll)]
 #![feature(control_flow_enum)]
 #![feature(try_blocks)]
 #![feature(associated_type_defaults)]
@@ -14,18 +13,17 @@
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{DefId, LocalDefId, LocalDefIdSet, CRATE_DEF_ID};
-use rustc_hir::intravisit::{self, DeepVisitor, Visitor};
-use rustc_hir::{AssocItemKind, HirIdSet, Node, PatKind};
+use rustc_hir::intravisit::{self, Visitor};
+use rustc_hir::{AssocItemKind, HirIdSet, ItemId, Node, PatKind};
 use rustc_middle::bug;
 use rustc_middle::hir::nested_filter;
 use rustc_middle::middle::privacy::{AccessLevel, AccessLevels};
 use rustc_middle::span_bug;
 use rustc_middle::thir::abstract_const::Node as ACNode;
-use rustc_middle::ty::fold::TypeVisitor;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::subst::InternalSubsts;
 use rustc_middle::ty::{self, Const, DefIdTree, GenericParamDefKind};
-use rustc_middle::ty::{TraitRef, Ty, TyCtxt, TypeFoldable};
+use rustc_middle::ty::{TraitRef, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable, TypeVisitor};
 use rustc_session::lint;
 use rustc_span::hygiene::Transparency;
 use rustc_span::symbol::{kw, Ident};
@@ -182,7 +180,8 @@
 
     fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<V::BreakTy> {
         let tcx = self.def_id_visitor.tcx();
-        // InternalSubsts are not visited here because they are visited below in `super_visit_with`.
+        // InternalSubsts are not visited here because they are visited below
+        // in `super_visit_with`.
         match *ty.kind() {
             ty::Adt(ty::AdtDef(Interned(&ty::AdtDefData { did: def_id, .. }, _)), ..)
             | ty::Foreign(def_id)
@@ -775,7 +774,14 @@
                         }
                         // Corner case: if the variant is reachable, but its
                         // enum is not, make the enum reachable as well.
-                        self.update(item.def_id, variant_level);
+                        self.reach(item.def_id, variant_level).ty();
+                    }
+                    if let Some(hir_id) = variant.data.ctor_hir_id() {
+                        let ctor_def_id = self.tcx.hir().local_def_id(hir_id);
+                        let ctor_level = self.get(ctor_def_id);
+                        if ctor_level.is_some() {
+                            self.reach(item.def_id, ctor_level).ty();
+                        }
                     }
                 }
             }
@@ -803,6 +809,13 @@
                         }
                     }
                 }
+                if let Some(hir_id) = struct_def.ctor_hir_id() {
+                    let ctor_def_id = self.tcx.hir().local_def_id(hir_id);
+                    let ctor_level = self.get(ctor_def_id);
+                    if ctor_level.is_some() {
+                        self.reach(item.def_id, ctor_level).ty();
+                    }
+                }
             }
         }
 
@@ -1802,12 +1815,12 @@
     }
 }
 
-struct PrivateItemsInPublicInterfacesVisitor<'tcx> {
+struct PrivateItemsInPublicInterfacesChecker<'tcx> {
     tcx: TyCtxt<'tcx>,
     old_error_set_ancestry: LocalDefIdSet,
 }
 
-impl<'tcx> PrivateItemsInPublicInterfacesVisitor<'tcx> {
+impl<'tcx> PrivateItemsInPublicInterfacesChecker<'tcx> {
     fn check(
         &self,
         def_id: LocalDefId,
@@ -1841,110 +1854,110 @@
             check.ty();
         }
     }
-}
 
-impl<'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'tcx> {
-    type NestedFilter = nested_filter::OnlyBodies;
-
-    fn nested_visit_map(&mut self) -> Self::Map {
-        self.tcx.hir()
-    }
-
-    fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
+    pub fn check_item(&mut self, id: ItemId) {
         let tcx = self.tcx;
-        let item_visibility = tcx.visibility(item.def_id);
+        let item_visibility = tcx.visibility(id.def_id);
+        let def_kind = tcx.def_kind(id.def_id);
 
-        match item.kind {
-            // Crates are always public.
-            hir::ItemKind::ExternCrate(..) => {}
-            // All nested items are checked by `visit_item`.
-            hir::ItemKind::Mod(..) => {}
-            // Checked in resolve.
-            hir::ItemKind::Use(..) => {}
-            // No subitems.
-            hir::ItemKind::Macro(..) | hir::ItemKind::GlobalAsm(..) => {}
-            // Subitems of these items have inherited publicity.
-            hir::ItemKind::Const(..)
-            | hir::ItemKind::Static(..)
-            | hir::ItemKind::Fn(..)
-            | hir::ItemKind::TyAlias(..) => {
-                self.check(item.def_id, item_visibility).generics().predicates().ty();
+        match def_kind {
+            DefKind::Const | DefKind::Static(_) | DefKind::Fn | DefKind::TyAlias => {
+                self.check(id.def_id, item_visibility).generics().predicates().ty();
             }
-            hir::ItemKind::OpaqueTy(..) => {
+            DefKind::OpaqueTy => {
                 // `ty()` for opaque types is the underlying type,
                 // it's not a part of interface, so we skip it.
-                self.check(item.def_id, item_visibility).generics().bounds();
+                self.check(id.def_id, item_visibility).generics().bounds();
             }
-            hir::ItemKind::Trait(.., trait_item_refs) => {
-                self.check(item.def_id, item_visibility).generics().predicates();
+            DefKind::Trait => {
+                let item = tcx.hir().item(id);
+                if let hir::ItemKind::Trait(.., trait_item_refs) = item.kind {
+                    self.check(item.def_id, item_visibility).generics().predicates();
 
-                for trait_item_ref in trait_item_refs {
-                    self.check_assoc_item(
-                        trait_item_ref.id.def_id,
-                        trait_item_ref.kind,
-                        trait_item_ref.defaultness,
-                        item_visibility,
-                    );
+                    for trait_item_ref in trait_item_refs {
+                        self.check_assoc_item(
+                            trait_item_ref.id.def_id,
+                            trait_item_ref.kind,
+                            trait_item_ref.defaultness,
+                            item_visibility,
+                        );
 
-                    if let AssocItemKind::Type = trait_item_ref.kind {
-                        self.check(trait_item_ref.id.def_id, item_visibility).bounds();
+                        if let AssocItemKind::Type = trait_item_ref.kind {
+                            self.check(trait_item_ref.id.def_id, item_visibility).bounds();
+                        }
                     }
                 }
             }
-            hir::ItemKind::TraitAlias(..) => {
-                self.check(item.def_id, item_visibility).generics().predicates();
+            DefKind::TraitAlias => {
+                self.check(id.def_id, item_visibility).generics().predicates();
             }
-            hir::ItemKind::Enum(ref def, _) => {
-                self.check(item.def_id, item_visibility).generics().predicates();
+            DefKind::Enum => {
+                let item = tcx.hir().item(id);
+                if let hir::ItemKind::Enum(ref def, _) = item.kind {
+                    self.check(item.def_id, item_visibility).generics().predicates();
 
-                for variant in def.variants {
-                    for field in variant.data.fields() {
-                        self.check(self.tcx.hir().local_def_id(field.hir_id), item_visibility).ty();
+                    for variant in def.variants {
+                        for field in variant.data.fields() {
+                            self.check(self.tcx.hir().local_def_id(field.hir_id), item_visibility)
+                                .ty();
+                        }
                     }
                 }
             }
             // Subitems of foreign modules have their own publicity.
-            hir::ItemKind::ForeignMod { items, .. } => {
-                for foreign_item in items {
-                    let vis = tcx.visibility(foreign_item.id.def_id);
-                    self.check(foreign_item.id.def_id, vis).generics().predicates().ty();
+            DefKind::ForeignMod => {
+                let item = tcx.hir().item(id);
+                if let hir::ItemKind::ForeignMod { items, .. } = item.kind {
+                    for foreign_item in items {
+                        let vis = tcx.visibility(foreign_item.id.def_id);
+                        self.check(foreign_item.id.def_id, vis).generics().predicates().ty();
+                    }
                 }
             }
             // Subitems of structs and unions have their own publicity.
-            hir::ItemKind::Struct(ref struct_def, _) | hir::ItemKind::Union(ref struct_def, _) => {
-                self.check(item.def_id, item_visibility).generics().predicates();
+            DefKind::Struct | DefKind::Union => {
+                let item = tcx.hir().item(id);
+                if let hir::ItemKind::Struct(ref struct_def, _)
+                | hir::ItemKind::Union(ref struct_def, _) = item.kind
+                {
+                    self.check(item.def_id, item_visibility).generics().predicates();
 
-                for field in struct_def.fields() {
-                    let def_id = tcx.hir().local_def_id(field.hir_id);
-                    let field_visibility = tcx.visibility(def_id);
-                    self.check(def_id, min(item_visibility, field_visibility, tcx)).ty();
+                    for field in struct_def.fields() {
+                        let def_id = tcx.hir().local_def_id(field.hir_id);
+                        let field_visibility = tcx.visibility(def_id);
+                        self.check(def_id, min(item_visibility, field_visibility, tcx)).ty();
+                    }
                 }
             }
             // An inherent impl is public when its type is public
             // Subitems of inherent impls have their own publicity.
             // A trait impl is public when both its type and its trait are public
             // Subitems of trait impls have inherited publicity.
-            hir::ItemKind::Impl(ref impl_) => {
-                let impl_vis = ty::Visibility::of_impl(item.def_id, tcx, &Default::default());
-                // check that private components do not appear in the generics or predicates of inherent impls
-                // this check is intentionally NOT performed for impls of traits, per #90586
-                if impl_.of_trait.is_none() {
-                    self.check(item.def_id, impl_vis).generics().predicates();
-                }
-                for impl_item_ref in impl_.items {
-                    let impl_item_vis = if impl_.of_trait.is_none() {
-                        min(tcx.visibility(impl_item_ref.id.def_id), impl_vis, tcx)
-                    } else {
-                        impl_vis
-                    };
-                    self.check_assoc_item(
-                        impl_item_ref.id.def_id,
-                        impl_item_ref.kind,
-                        impl_item_ref.defaultness,
-                        impl_item_vis,
-                    );
+            DefKind::Impl => {
+                let item = tcx.hir().item(id);
+                if let hir::ItemKind::Impl(ref impl_) = item.kind {
+                    let impl_vis = ty::Visibility::of_impl(item.def_id, tcx, &Default::default());
+                    // check that private components do not appear in the generics or predicates of inherent impls
+                    // this check is intentionally NOT performed for impls of traits, per #90586
+                    if impl_.of_trait.is_none() {
+                        self.check(item.def_id, impl_vis).generics().predicates();
+                    }
+                    for impl_item_ref in impl_.items {
+                        let impl_item_vis = if impl_.of_trait.is_none() {
+                            min(tcx.visibility(impl_item_ref.id.def_id), impl_vis, tcx)
+                        } else {
+                            impl_vis
+                        };
+                        self.check_assoc_item(
+                            impl_item_ref.id.def_id,
+                            impl_item_ref.kind,
+                            impl_item_ref.defaultness,
+                            impl_item_vis,
+                        );
+                    }
                 }
             }
+            _ => {}
         }
     }
 }
@@ -1968,7 +1981,7 @@
             match tcx.hir().get(hir_id) {
                 // Unique types created for closures participate in type privacy checking.
                 // They have visibilities inherited from the module they are defined in.
-                Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(..), .. })
+                Node::Expr(hir::Expr { kind: hir::ExprKind::Closure{..}, .. })
                 // - AST lowering creates dummy `use` items which don't
                 //   get their entries in the resolver's visibility table.
                 // - AST lowering also creates opaque type items with inherited visibilities.
@@ -2069,7 +2082,7 @@
     }
 
     // Check for private types and traits in public interfaces.
-    let mut visitor = PrivateItemsInPublicInterfacesVisitor {
+    let mut checker = PrivateItemsInPublicInterfacesChecker {
         tcx,
         // Only definition IDs are ever searched in `old_error_set_ancestry`,
         // so we can filter away all non-definition IDs at this point.
@@ -2078,5 +2091,8 @@
             .filter_map(|hir_id| tcx.hir().opt_local_def_id(hir_id))
             .collect(),
     };
-    tcx.hir().visit_all_item_likes(&mut DeepVisitor::new(&mut visitor));
+
+    for id in tcx.hir().items() {
+        checker.check_item(id);
+    }
 }
diff --git a/compiler/rustc_query_impl/Cargo.toml b/compiler/rustc_query_impl/Cargo.toml
index fa05434..5673bb8 100644
--- a/compiler/rustc_query_impl/Cargo.toml
+++ b/compiler/rustc_query_impl/Cargo.toml
@@ -8,7 +8,7 @@
 
 [dependencies]
 measureme = "10.0.0"
-rustc-rayon-core = { version = "0.3.2", optional = true }
+rustc-rayon-core = { version = "0.4.0", optional = true }
 rustc_ast = { path = "../rustc_ast" }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_errors = { path = "../rustc_errors" }
diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs
index 6ebff53..d06eb97 100644
--- a/compiler/rustc_query_impl/src/lib.rs
+++ b/compiler/rustc_query_impl/src/lib.rs
@@ -1,9 +1,8 @@
 //! Support for serializing the dep-graph and reloading it.
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
-#![feature(crate_visibility_modifier)]
-#![feature(nll)]
 #![feature(min_specialization)]
+#![feature(never_type)]
 #![feature(once_cell)]
 #![feature(rustc_attrs)]
 #![recursion_limit = "256"]
@@ -21,7 +20,7 @@
 use rustc_middle::ty::query::{query_keys, query_storage, query_stored, query_values};
 use rustc_middle::ty::query::{ExternProviders, Providers, QueryEngine};
 use rustc_middle::ty::{self, TyCtxt};
-use rustc_span::def_id::LocalDefId;
+use rustc_span::def_id::{LocalDefId, LOCAL_CRATE};
 use rustc_span::Span;
 
 #[macro_use]
diff --git a/compiler/rustc_query_impl/src/on_disk_cache.rs b/compiler/rustc_query_impl/src/on_disk_cache.rs
index f2f8953..b01c512 100644
--- a/compiler/rustc_query_impl/src/on_disk_cache.rs
+++ b/compiler/rustc_query_impl/src/on_disk_cache.rs
@@ -15,7 +15,7 @@
 use rustc_query_system::dep_graph::DepContext;
 use rustc_query_system::query::{QueryCache, QueryContext, QuerySideEffects};
 use rustc_serialize::{
-    opaque::{self, FileEncodeResult, FileEncoder, IntEncodedWithFixedSize},
+    opaque::{FileEncodeResult, FileEncoder, IntEncodedWithFixedSize, MemDecoder},
     Decodable, Decoder, Encodable, Encoder,
 };
 use rustc_session::Session;
@@ -25,6 +25,7 @@
 use rustc_span::source_map::{SourceMap, StableSourceFileId};
 use rustc_span::CachingSourceMapView;
 use rustc_span::{BytePos, ExpnData, ExpnHash, Pos, SourceFile, Span};
+use std::io;
 use std::mem;
 
 const TAG_FILE_FOOTER: u128 = 0xC0FFEE_C0FFEE_C0FFEE_C0FFEE_C0FFEE;
@@ -158,7 +159,7 @@
 
         // Wrap in a scope so we can borrow `data`.
         let footer: Footer = {
-            let mut decoder = opaque::Decoder::new(&data, start_pos);
+            let mut decoder = MemDecoder::new(&data, start_pos);
 
             // Decode the *position* of the footer, which can be found in the
             // last 8 bytes of the file.
@@ -221,7 +222,7 @@
         *self.serialized_data.write() = None;
     }
 
-    fn serialize<'tcx>(&self, tcx: TyCtxt<'tcx>, encoder: &mut FileEncoder) -> FileEncodeResult {
+    fn serialize<'tcx>(&self, tcx: TyCtxt<'tcx>, encoder: FileEncoder) -> FileEncodeResult {
         // Serializing the `DepGraph` should not modify it.
         tcx.dep_graph.with_ignore(|| {
             // Allocate `SourceFileIndex`es.
@@ -259,27 +260,25 @@
             // Encode query results.
             let mut query_result_index = EncodedDepNodeIndex::new();
 
-            tcx.sess.time("encode_query_results", || -> FileEncodeResult {
+            tcx.sess.time("encode_query_results", || {
                 let enc = &mut encoder;
                 let qri = &mut query_result_index;
-                QueryCtxt::from_tcx(tcx).encode_query_results(enc, qri)
-            })?;
+                QueryCtxt::from_tcx(tcx).encode_query_results(enc, qri);
+            });
 
             // Encode side effects.
             let side_effects_index: EncodedDepNodeIndex = self
                 .current_side_effects
                 .borrow()
                 .iter()
-                .map(
-                    |(dep_node_index, side_effects)| -> Result<_, <FileEncoder as Encoder>::Error> {
-                        let pos = AbsoluteBytePos::new(encoder.position());
-                        let dep_node_index = SerializedDepNodeIndex::new(dep_node_index.index());
-                        encoder.encode_tagged(dep_node_index, side_effects)?;
+                .map(|(dep_node_index, side_effects)| {
+                    let pos = AbsoluteBytePos::new(encoder.position());
+                    let dep_node_index = SerializedDepNodeIndex::new(dep_node_index.index());
+                    encoder.encode_tagged(dep_node_index, side_effects);
 
-                        Ok((dep_node_index, pos))
-                    },
-                )
-                .collect::<Result<_, _>>()?;
+                    (dep_node_index, pos)
+                })
+                .collect();
 
             let interpret_alloc_index = {
                 let mut interpret_alloc_index = Vec::new();
@@ -296,7 +295,7 @@
                         let id = encoder.interpret_allocs[idx];
                         let pos = encoder.position() as u32;
                         interpret_alloc_index.push(pos);
-                        interpret::specialized_encode_alloc_id(&mut encoder, tcx, id)?;
+                        interpret::specialized_encode_alloc_id(&mut encoder, tcx, id);
                     }
                     n = new_n;
                 }
@@ -312,23 +311,21 @@
 
             hygiene_encode_context.encode(
                 &mut encoder,
-                |encoder, index, ctxt_data| -> FileEncodeResult {
+                |encoder, index, ctxt_data| {
                     let pos = AbsoluteBytePos::new(encoder.position());
-                    encoder.encode_tagged(TAG_SYNTAX_CONTEXT, ctxt_data)?;
+                    encoder.encode_tagged(TAG_SYNTAX_CONTEXT, ctxt_data);
                     syntax_contexts.insert(index, pos);
-                    Ok(())
                 },
-                |encoder, expn_id, data, hash| -> FileEncodeResult {
+                |encoder, expn_id, data, hash| {
                     if expn_id.krate == LOCAL_CRATE {
                         let pos = AbsoluteBytePos::new(encoder.position());
-                        encoder.encode_tagged(TAG_EXPN_DATA, data)?;
+                        encoder.encode_tagged(TAG_EXPN_DATA, data);
                         expn_data.insert(hash, pos);
                     } else {
                         foreign_expn_data.insert(hash, expn_id.local_id.as_u32());
                     }
-                    Ok(())
                 },
-            )?;
+            );
 
             // `Encode the file footer.
             let footer_pos = encoder.position() as u64;
@@ -343,16 +340,16 @@
                     expn_data,
                     foreign_expn_data,
                 },
-            )?;
+            );
 
             // Encode the position of the footer as the last 8 bytes of the
             // file so we know where to look for it.
-            IntEncodedWithFixedSize(footer_pos).encode(encoder.encoder)?;
+            IntEncodedWithFixedSize(footer_pos).encode(&mut encoder.encoder);
 
             // DO NOT WRITE ANYTHING TO THE ENCODER AFTER THIS POINT! The address
             // of the footer must be the last thing in the data stream.
 
-            Ok(())
+            encoder.finish()
         })
     }
 }
@@ -441,7 +438,7 @@
         let serialized_data = self.serialized_data.read();
         let mut decoder = CacheDecoder {
             tcx,
-            opaque: opaque::Decoder::new(serialized_data.as_deref().unwrap_or(&[]), pos.to_usize()),
+            opaque: MemDecoder::new(serialized_data.as_deref().unwrap_or(&[]), pos.to_usize()),
             source_map: self.source_map,
             file_index_to_file: &self.file_index_to_file,
             file_index_to_stable_id: &self.file_index_to_stable_id,
@@ -462,7 +459,7 @@
 /// will also handle things that contain `Ty` instances.
 pub struct CacheDecoder<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
-    opaque: opaque::Decoder<'a>,
+    opaque: MemDecoder<'a>,
     source_map: &'a SourceMap,
     file_index_to_file: &'a Lock<FxHashMap<SourceFileIndex, Lrc<SourceFile>>>,
     file_index_to_stable_id: &'a FxHashMap<SourceFileIndex, EncodedSourceFileId>,
@@ -514,7 +511,7 @@
     fn position(&self) -> usize;
 }
 
-impl<'a> DecoderWithPosition for opaque::Decoder<'a> {
+impl<'a> DecoderWithPosition for MemDecoder<'a> {
     fn position(&self) -> usize {
         self.position()
     }
@@ -547,11 +544,12 @@
     value
 }
 
-impl<'a, 'tcx> TyDecoder<'tcx> for CacheDecoder<'a, 'tcx> {
+impl<'a, 'tcx> TyDecoder for CacheDecoder<'a, 'tcx> {
+    type I = TyCtxt<'tcx>;
     const CLEAR_CROSS_CRATE: bool = false;
 
     #[inline]
-    fn tcx(&self) -> TyCtxt<'tcx> {
+    fn interner(&self) -> TyCtxt<'tcx> {
         self.tcx
     }
 
@@ -569,7 +567,7 @@
     where
         F: FnOnce(&mut Self) -> Ty<'tcx>,
     {
-        let tcx = self.tcx();
+        let tcx = self.tcx;
 
         let cache_key = ty::CReaderCacheKey { cnum: None, pos: shorthand };
 
@@ -589,7 +587,7 @@
     {
         debug_assert!(pos < self.opaque.data.len());
 
-        let new_opaque = opaque::Decoder::new(self.opaque.data, pos);
+        let new_opaque = MemDecoder::new(self.opaque.data, pos);
         let old_opaque = mem::replace(&mut self.opaque, new_opaque);
         let r = f(self);
         self.opaque = old_opaque;
@@ -692,8 +690,7 @@
             let dlo = u32::decode(decoder);
             let dto = u32::decode(decoder);
 
-            let enclosing =
-                decoder.tcx.definitions_untracked().def_span(parent.unwrap()).data_untracked();
+            let enclosing = decoder.tcx.source_span_untracked(parent.unwrap()).data_untracked();
             let span = Span::new(
                 enclosing.lo + BytePos::from_u32(dlo),
                 enclosing.lo + BytePos::from_u32(dto),
@@ -712,7 +709,7 @@
         let len = BytePos::decode(decoder);
 
         let file_lo = decoder.file_index_to_file(file_lo_index);
-        let lo = file_lo.lines[line_lo - 1] + col_lo;
+        let lo = file_lo.lines(|lines| lines[line_lo - 1] + col_lo);
         let hi = lo + len;
 
         Span::new(lo, hi, ctxt, parent)
@@ -750,7 +747,7 @@
         // If we get to this point, then all of the query inputs were green,
         // which means that the definition with this hash is guaranteed to
         // still exist in the current compilation session.
-        d.tcx().def_path_hash_to_def_id(def_path_hash, &mut || {
+        d.tcx.def_path_hash_to_def_id(def_path_hash, &mut || {
             panic!("Failed to convert DefPathHash {:?}", def_path_hash)
         })
     }
@@ -788,29 +785,32 @@
     }
 }
 
-impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx [Span] {
-    fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self {
-        RefDecodable::decode(d)
-    }
+macro_rules! impl_ref_decoder {
+    (<$tcx:tt> $($ty:ty,)*) => {
+        $(impl<'a, $tcx> Decodable<CacheDecoder<'a, $tcx>> for &$tcx [$ty] {
+            fn decode(d: &mut CacheDecoder<'a, $tcx>) -> Self {
+                RefDecodable::decode(d)
+            }
+        })*
+    };
+}
+
+impl_ref_decoder! {<'tcx>
+    Span,
+    rustc_ast::Attribute,
+    rustc_span::symbol::Ident,
+    ty::Variance,
+    rustc_span::def_id::DefId,
+    rustc_span::def_id::LocalDefId,
+    (rustc_middle::middle::exported_symbols::ExportedSymbol<'tcx>, rustc_middle::middle::exported_symbols::SymbolExportInfo),
 }
 
 //- ENCODING -------------------------------------------------------------------
 
-pub trait OpaqueEncoder: Encoder {
-    fn position(&self) -> usize;
-}
-
-impl OpaqueEncoder for FileEncoder {
-    #[inline]
-    fn position(&self) -> usize {
-        FileEncoder::position(self)
-    }
-}
-
 /// An encoder that can write to the incremental compilation cache.
-pub struct CacheEncoder<'a, 'tcx, E: OpaqueEncoder> {
+pub struct CacheEncoder<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
-    encoder: &'a mut E,
+    encoder: FileEncoder,
     type_shorthands: FxHashMap<Ty<'tcx>, usize>,
     predicate_shorthands: FxHashMap<ty::PredicateKind<'tcx>, usize>,
     interpret_allocs: FxIndexSet<interpret::AllocId>,
@@ -819,10 +819,7 @@
     hygiene_context: &'a HygieneEncodeContext,
 }
 
-impl<'a, 'tcx, E> CacheEncoder<'a, 'tcx, E>
-where
-    E: 'a + OpaqueEncoder,
-{
+impl<'a, 'tcx> CacheEncoder<'a, 'tcx> {
     fn source_file_index(&mut self, source_file: Lrc<SourceFile>) -> SourceFileIndex {
         self.file_to_file_index[&(&*source_file as *const SourceFile)]
     }
@@ -832,60 +829,51 @@
     /// encode the specified tag, then the given value, then the number of
     /// bytes taken up by tag and value. On decoding, we can then verify that
     /// we get the expected tag and read the expected number of bytes.
-    fn encode_tagged<T: Encodable<Self>, V: Encodable<Self>>(
-        &mut self,
-        tag: T,
-        value: &V,
-    ) -> Result<(), E::Error> {
+    fn encode_tagged<T: Encodable<Self>, V: Encodable<Self>>(&mut self, tag: T, value: &V) {
         let start_pos = self.position();
 
-        tag.encode(self)?;
-        value.encode(self)?;
+        tag.encode(self);
+        value.encode(self);
 
         let end_pos = self.position();
-        ((end_pos - start_pos) as u64).encode(self)
+        ((end_pos - start_pos) as u64).encode(self);
+    }
+
+    fn finish(self) -> Result<usize, io::Error> {
+        self.encoder.finish()
     }
 }
 
-impl<'a, 'tcx, E> Encodable<CacheEncoder<'a, 'tcx, E>> for SyntaxContext
-where
-    E: 'a + OpaqueEncoder,
-{
-    fn encode(&self, s: &mut CacheEncoder<'a, 'tcx, E>) -> Result<(), E::Error> {
-        rustc_span::hygiene::raw_encode_syntax_context(*self, s.hygiene_context, s)
+impl<'a, 'tcx> Encodable<CacheEncoder<'a, 'tcx>> for SyntaxContext {
+    fn encode(&self, s: &mut CacheEncoder<'a, 'tcx>) {
+        rustc_span::hygiene::raw_encode_syntax_context(*self, s.hygiene_context, s);
     }
 }
 
-impl<'a, 'tcx, E> Encodable<CacheEncoder<'a, 'tcx, E>> for ExpnId
-where
-    E: 'a + OpaqueEncoder,
-{
-    fn encode(&self, s: &mut CacheEncoder<'a, 'tcx, E>) -> Result<(), E::Error> {
+impl<'a, 'tcx> Encodable<CacheEncoder<'a, 'tcx>> for ExpnId {
+    fn encode(&self, s: &mut CacheEncoder<'a, 'tcx>) {
         s.hygiene_context.schedule_expn_data_for_encoding(*self);
-        self.expn_hash().encode(s)
+        self.expn_hash().encode(s);
     }
 }
 
-impl<'a, 'tcx, E> Encodable<CacheEncoder<'a, 'tcx, E>> for Span
-where
-    E: 'a + OpaqueEncoder,
-{
-    fn encode(&self, s: &mut CacheEncoder<'a, 'tcx, E>) -> Result<(), E::Error> {
+impl<'a, 'tcx> Encodable<CacheEncoder<'a, 'tcx>> for Span {
+    fn encode(&self, s: &mut CacheEncoder<'a, 'tcx>) {
         let span_data = self.data_untracked();
-        span_data.ctxt.encode(s)?;
-        span_data.parent.encode(s)?;
+        span_data.ctxt.encode(s);
+        span_data.parent.encode(s);
 
         if span_data.is_dummy() {
             return TAG_PARTIAL_SPAN.encode(s);
         }
 
         if let Some(parent) = span_data.parent {
-            let enclosing = s.tcx.definitions_untracked().def_span(parent).data_untracked();
+            let enclosing = s.tcx.source_span(parent).data_untracked();
             if enclosing.contains(span_data) {
-                TAG_RELATIVE_SPAN.encode(s)?;
-                (span_data.lo - enclosing.lo).to_u32().encode(s)?;
-                (span_data.hi - enclosing.lo).to_u32().encode(s)?;
-                return Ok(());
+                TAG_RELATIVE_SPAN.encode(s);
+                (span_data.lo - enclosing.lo).to_u32().encode(s);
+                (span_data.hi - enclosing.lo).to_u32().encode(s);
+                return;
             }
         }
 
@@ -905,18 +893,16 @@
 
         let source_file_index = s.source_file_index(file_lo);
 
-        TAG_FULL_SPAN.encode(s)?;
-        source_file_index.encode(s)?;
-        line_lo.encode(s)?;
-        col_lo.encode(s)?;
-        len.encode(s)
+        TAG_FULL_SPAN.encode(s);
+        source_file_index.encode(s);
+        line_lo.encode(s);
+        col_lo.encode(s);
+        len.encode(s);
     }
 }
 
-impl<'a, 'tcx, E> TyEncoder<'tcx> for CacheEncoder<'a, 'tcx, E>
-where
-    E: 'a + OpaqueEncoder,
-{
+impl<'a, 'tcx> TyEncoder for CacheEncoder<'a, 'tcx> {
+    type I = TyCtxt<'tcx>;
     const CLEAR_CROSS_CRATE: bool = false;
 
     fn position(&self) -> usize {
@@ -928,36 +914,27 @@
     fn predicate_shorthands(&mut self) -> &mut FxHashMap<ty::PredicateKind<'tcx>, usize> {
         &mut self.predicate_shorthands
     }
-    fn encode_alloc_id(&mut self, alloc_id: &interpret::AllocId) -> Result<(), Self::Error> {
+    fn encode_alloc_id(&mut self, alloc_id: &interpret::AllocId) {
         let (index, _) = self.interpret_allocs.insert_full(*alloc_id);
 
-        index.encode(self)
+        index.encode(self);
     }
 }
 
-impl<'a, 'tcx, E> Encodable<CacheEncoder<'a, 'tcx, E>> for CrateNum
-where
-    E: 'a + OpaqueEncoder,
-{
-    fn encode(&self, s: &mut CacheEncoder<'a, 'tcx, E>) -> Result<(), E::Error> {
-        s.tcx.stable_crate_id(*self).encode(s)
+impl<'a, 'tcx> Encodable<CacheEncoder<'a, 'tcx>> for CrateNum {
+    fn encode(&self, s: &mut CacheEncoder<'a, 'tcx>) {
+        s.tcx.stable_crate_id(*self).encode(s);
     }
 }
 
-impl<'a, 'tcx, E> Encodable<CacheEncoder<'a, 'tcx, E>> for DefId
-where
-    E: 'a + OpaqueEncoder,
-{
-    fn encode(&self, s: &mut CacheEncoder<'a, 'tcx, E>) -> Result<(), E::Error> {
-        s.tcx.def_path_hash(*self).encode(s)
+impl<'a, 'tcx> Encodable<CacheEncoder<'a, 'tcx>> for DefId {
+    fn encode(&self, s: &mut CacheEncoder<'a, 'tcx>) {
+        s.tcx.def_path_hash(*self).encode(s);
     }
 }
 
-impl<'a, 'tcx, E> Encodable<CacheEncoder<'a, 'tcx, E>> for DefIndex
-where
-    E: 'a + OpaqueEncoder,
-{
-    fn encode(&self, _: &mut CacheEncoder<'a, 'tcx, E>) -> Result<(), E::Error> {
+impl<'a, 'tcx> Encodable<CacheEncoder<'a, 'tcx>> for DefIndex {
+    fn encode(&self, _: &mut CacheEncoder<'a, 'tcx>) {
         bug!("encoding `DefIndex` without context");
     }
 }
@@ -965,23 +942,13 @@
 macro_rules! encoder_methods {
     ($($name:ident($ty:ty);)*) => {
         #[inline]
-        $(fn $name(&mut self, value: $ty) -> Result<(), Self::Error> {
+        $(fn $name(&mut self, value: $ty) {
             self.encoder.$name(value)
         })*
     }
 }
 
-impl<'a, 'tcx, E> Encoder for CacheEncoder<'a, 'tcx, E>
-where
-    E: 'a + OpaqueEncoder,
-{
-    type Error = E::Error;
-
-    #[inline]
-    fn emit_unit(&mut self) -> Result<(), Self::Error> {
-        Ok(())
-    }
-
+impl<'a, 'tcx> Encoder for CacheEncoder<'a, 'tcx> {
     encoder_methods! {
         emit_usize(usize);
         emit_u128(u128);
@@ -1010,21 +977,20 @@
 // is used when a `CacheEncoder` having an `opaque::FileEncoder` is passed to `Encodable::encode`.
 // Unfortunately, we have to manually opt into specializations this way, given how `CacheEncoder`
 // and the encoding traits currently work.
-impl<'a, 'tcx> Encodable<CacheEncoder<'a, 'tcx, FileEncoder>> for [u8] {
-    fn encode(&self, e: &mut CacheEncoder<'a, 'tcx, FileEncoder>) -> FileEncodeResult {
-        self.encode(e.encoder)
+impl<'a, 'tcx> Encodable<CacheEncoder<'a, 'tcx>> for [u8] {
+    fn encode(&self, e: &mut CacheEncoder<'a, 'tcx>) {
+        self.encode(&mut e.encoder);
     }
 }
 
 pub fn encode_query_results<'a, 'tcx, CTX, Q>(
     tcx: CTX,
-    encoder: &mut CacheEncoder<'a, 'tcx, FileEncoder>,
+    encoder: &mut CacheEncoder<'a, 'tcx>,
     query_result_index: &mut EncodedDepNodeIndex,
-) -> FileEncodeResult
-where
+) where
     CTX: QueryContext + 'tcx,
     Q: super::QueryDescription<CTX>,
-    Q::Value: Encodable<CacheEncoder<'a, 'tcx, FileEncoder>>,
+    Q::Value: Encodable<CacheEncoder<'a, 'tcx>>,
 {
     let _timer = tcx
         .dep_context()
@@ -1033,11 +999,7 @@
 
     assert!(Q::query_state(tcx).all_inactive());
     let cache = Q::query_cache(tcx);
-    let mut res = Ok(());
     cache.iter(&mut |key, value, dep_node| {
-        if res.is_err() {
-            return;
-        }
         if Q::cache_on_disk(*tcx.dep_context(), &key) {
             let dep_node = SerializedDepNodeIndex::new(dep_node.index());
 
@@ -1046,14 +1008,7 @@
 
             // Encode the type check tables with the `SerializedDepNodeIndex`
             // as tag.
-            match encoder.encode_tagged(dep_node, value) {
-                Ok(()) => {}
-                Err(e) => {
-                    res = Err(e);
-                }
-            }
+            encoder.encode_tagged(dep_node, value);
         }
     });
-
-    res
 }
diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs
index ae4ad42..66f4508 100644
--- a/compiler/rustc_query_impl/src/plumbing.rs
+++ b/compiler/rustc_query_impl/src/plumbing.rs
@@ -12,7 +12,6 @@
 use rustc_data_structures::sync::Lock;
 use rustc_data_structures::thin_vec::ThinVec;
 use rustc_errors::{Diagnostic, Handler};
-use rustc_serialize::opaque;
 
 use std::any::Any;
 use std::num::NonZeroU64;
@@ -129,7 +128,7 @@
         QueryCtxt { tcx, queries }
     }
 
-    crate fn on_disk_cache(self) -> Option<&'tcx on_disk_cache::OnDiskCache<'tcx>> {
+    pub(crate) fn on_disk_cache(self) -> Option<&'tcx on_disk_cache::OnDiskCache<'tcx>> {
         self.queries.on_disk_cache.as_ref()
     }
 
@@ -140,9 +139,9 @@
 
     pub(super) fn encode_query_results(
         self,
-        encoder: &mut on_disk_cache::CacheEncoder<'_, 'tcx, opaque::FileEncoder>,
+        encoder: &mut on_disk_cache::CacheEncoder<'_, 'tcx>,
         query_result_index: &mut on_disk_cache::EncodedDepNodeIndex,
-    ) -> opaque::FileEncodeResult {
+    ) {
         macro_rules! encode_queries {
             ($($query:ident,)*) => {
                 $(
@@ -150,14 +149,12 @@
                         self,
                         encoder,
                         query_result_index
-                    )?;
+                    );
                 )*
             }
         }
 
         rustc_cached_queries!(encode_queries!);
-
-        Ok(())
     }
 
     pub fn try_print_query_stack(
diff --git a/compiler/rustc_query_impl/src/profiling_support.rs b/compiler/rustc_query_impl/src/profiling_support.rs
index b20aa7b..551f094 100644
--- a/compiler/rustc_query_impl/src/profiling_support.rs
+++ b/compiler/rustc_query_impl/src/profiling_support.rs
@@ -275,6 +275,9 @@
             let query_name = profiler.get_or_alloc_cached_string(query_name);
             let event_id = event_id_builder.from_label(query_name).to_string_id();
 
+            // FIXME(eddyb) make this O(1) by using a pre-cached query name `EventId`,
+            // instead of passing the `DepNodeIndex` to `finish_with_query_invocation_id`,
+            // when recording the event in the first place.
             let mut query_invocation_ids = Vec::new();
             query_cache.iter(&mut |_, _, i| {
                 query_invocation_ids.push(i.into());
diff --git a/compiler/rustc_query_system/Cargo.toml b/compiler/rustc_query_system/Cargo.toml
index 8a35121..b5a37cf 100644
--- a/compiler/rustc_query_system/Cargo.toml
+++ b/compiler/rustc_query_system/Cargo.toml
@@ -9,7 +9,7 @@
 [dependencies]
 rustc_arena = { path = "../rustc_arena" }
 tracing = "0.1"
-rustc-rayon-core = { version = "0.3.2", optional = true }
+rustc-rayon-core = { version = "0.4.0", optional = true }
 rustc_ast = { path = "../rustc_ast" }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_errors = { path = "../rustc_errors" }
diff --git a/compiler/rustc_query_system/src/dep_graph/dep_node.rs b/compiler/rustc_query_system/src/dep_graph/dep_node.rs
index c274c2c..bb2179a 100644
--- a/compiler/rustc_query_system/src/dep_graph/dep_node.rs
+++ b/compiler/rustc_query_system/src/dep_graph/dep_node.rs
@@ -164,7 +164,6 @@
 impl WorkProductId {
     pub fn from_cgu_name(cgu_name: &str) -> WorkProductId {
         let mut hasher = StableHasher::new();
-        cgu_name.len().hash(&mut hasher);
         cgu_name.hash(&mut hasher);
         WorkProductId { hash: hasher.finish() }
     }
diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs
index f7655e5..341cf8f 100644
--- a/compiler/rustc_query_system/src/dep_graph/graph.rs
+++ b/compiler/rustc_query_system/src/dep_graph/graph.rs
@@ -750,7 +750,7 @@
             dep_node
         );
 
-        if unlikely!(!side_effects.is_empty()) {
+        if !side_effects.is_empty() {
             self.emit_side_effects(tcx, data, dep_node_index, side_effects);
         }
 
@@ -842,7 +842,7 @@
         if let Some(data) = &self.data {
             data.current.encoder.steal().finish(profiler)
         } else {
-            Ok(())
+            Ok(0)
         }
     }
 
@@ -887,7 +887,7 @@
 pub struct WorkProduct {
     pub cgu_name: String,
     /// Saved file associated with this CGU.
-    pub saved_file: Option<String>,
+    pub saved_file: String,
 }
 
 // Index type for `DepNodeData`'s edges.
diff --git a/compiler/rustc_query_system/src/dep_graph/serialized.rs b/compiler/rustc_query_system/src/dep_graph/serialized.rs
index 1f8d87a..3b20ec7 100644
--- a/compiler/rustc_query_system/src/dep_graph/serialized.rs
+++ b/compiler/rustc_query_system/src/dep_graph/serialized.rs
@@ -19,7 +19,7 @@
 use rustc_data_structures::profiling::SelfProfilerRef;
 use rustc_data_structures::sync::Lock;
 use rustc_index::vec::{Idx, IndexVec};
-use rustc_serialize::opaque::{self, FileEncodeResult, FileEncoder, IntEncodedWithFixedSize};
+use rustc_serialize::opaque::{FileEncodeResult, FileEncoder, IntEncodedWithFixedSize, MemDecoder};
 use rustc_serialize::{Decodable, Decoder, Encodable};
 use smallvec::SmallVec;
 use std::convert::TryInto;
@@ -96,11 +96,11 @@
     }
 }
 
-impl<'a, K: DepKind + Decodable<opaque::Decoder<'a>>> Decodable<opaque::Decoder<'a>>
+impl<'a, K: DepKind + Decodable<MemDecoder<'a>>> Decodable<MemDecoder<'a>>
     for SerializedDepGraph<K>
 {
     #[instrument(level = "debug", skip(d))]
-    fn decode(d: &mut opaque::Decoder<'a>) -> SerializedDepGraph<K> {
+    fn decode(d: &mut MemDecoder<'a>) -> SerializedDepGraph<K> {
         let start_position = d.position();
 
         // The last 16 bytes are the node count and edge count.
@@ -166,7 +166,6 @@
     encoder: FileEncoder,
     total_node_count: usize,
     total_edge_count: usize,
-    result: FileEncodeResult,
     stats: Option<FxHashMap<K, Stat<K>>>,
 }
 
@@ -176,7 +175,6 @@
             encoder,
             total_edge_count: 0,
             total_node_count: 0,
-            result: Ok(()),
             stats: record_stats.then(FxHashMap::default),
         }
     }
@@ -208,29 +206,28 @@
         }
 
         let encoder = &mut self.encoder;
-        if self.result.is_ok() {
-            self.result = node.encode(encoder);
-        }
+        node.encode(encoder);
         index
     }
 
     fn finish(self, profiler: &SelfProfilerRef) -> FileEncodeResult {
-        let Self { mut encoder, total_node_count, total_edge_count, result, stats: _ } = self;
-        let () = result?;
+        let Self { mut encoder, total_node_count, total_edge_count, stats: _ } = self;
 
         let node_count = total_node_count.try_into().unwrap();
         let edge_count = total_edge_count.try_into().unwrap();
 
         debug!(?node_count, ?edge_count);
         debug!("position: {:?}", encoder.position());
-        IntEncodedWithFixedSize(node_count).encode(&mut encoder)?;
-        IntEncodedWithFixedSize(edge_count).encode(&mut encoder)?;
+        IntEncodedWithFixedSize(node_count).encode(&mut encoder);
+        IntEncodedWithFixedSize(edge_count).encode(&mut encoder);
         debug!("position: {:?}", encoder.position());
         // Drop the encoder so that nothing is written after the counts.
-        let result = encoder.flush();
-        // FIXME(rylev): we hardcode the dep graph file name so we don't need a dependency on
-        // rustc_incremental just for that.
-        profiler.artifact_size("dep_graph", "dep-graph.bin", encoder.position() as u64);
+        let result = encoder.finish();
+        if let Ok(position) = result {
+            // FIXME(rylev): we hardcode the dep graph file name so we
+            // don't need a dependency on rustc_incremental just for that.
+            profiler.artifact_size("dep_graph", "dep-graph.bin", position as u64);
+        }
         result
     }
 }
diff --git a/compiler/rustc_query_system/src/ich/hcx.rs b/compiler/rustc_query_system/src/ich/hcx.rs
index 03ef857..62a1f77 100644
--- a/compiler/rustc_query_system/src/ich/hcx.rs
+++ b/compiler/rustc_query_system/src/ich/hcx.rs
@@ -1,23 +1,18 @@
 use crate::ich;
 use rustc_ast as ast;
-use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::sorted_map::SortedMap;
 use rustc_data_structures::stable_hasher::{HashStable, HashingControls, StableHasher};
 use rustc_data_structures::sync::Lrc;
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::definitions::{DefPathHash, Definitions};
+use rustc_index::vec::IndexVec;
 use rustc_session::cstore::CrateStore;
 use rustc_session::Session;
 use rustc_span::source_map::SourceMap;
 use rustc_span::symbol::Symbol;
 use rustc_span::{BytePos, CachingSourceMapView, SourceFile, Span, SpanData};
 
-fn compute_ignored_attr_names() -> FxHashSet<Symbol> {
-    debug_assert!(!ich::IGNORED_ATTRIBUTES.is_empty());
-    ich::IGNORED_ATTRIBUTES.iter().copied().collect()
-}
-
 /// This is the context state available during incr. comp. hashing. It contains
 /// enough information to transform `DefId`s and `HirId`s into stable `DefPath`s (i.e.,
 /// a reference to the `TyCtxt`) and it holds a few caches for speeding up various
@@ -26,6 +21,7 @@
 pub struct StableHashingContext<'a> {
     definitions: &'a Definitions,
     cstore: &'a dyn CrateStore,
+    source_span: &'a IndexVec<LocalDefId, Span>,
     // The value of `-Z incremental-ignore-spans`.
     // This field should only be used by `debug_opts_incremental_ignore_span`
     incremental_ignore_spans: bool,
@@ -56,6 +52,7 @@
         sess: &'a Session,
         definitions: &'a Definitions,
         cstore: &'a dyn CrateStore,
+        source_span: &'a IndexVec<LocalDefId, Span>,
         always_ignore_spans: bool,
     ) -> Self {
         let hash_spans_initial =
@@ -65,6 +62,7 @@
             body_resolver: BodyResolver::Forbidden,
             definitions,
             cstore,
+            source_span,
             incremental_ignore_spans: sess.opts.debugging_opts.incremental_ignore_spans,
             caching_source_map: None,
             raw_source_map: sess.source_map(),
@@ -77,11 +75,13 @@
         sess: &'a Session,
         definitions: &'a Definitions,
         cstore: &'a dyn CrateStore,
+        source_span: &'a IndexVec<LocalDefId, Span>,
     ) -> Self {
         Self::new_with_or_without_spans(
             sess,
             definitions,
             cstore,
+            source_span,
             /*always_ignore_spans=*/ false,
         )
     }
@@ -91,9 +91,10 @@
         sess: &'a Session,
         definitions: &'a Definitions,
         cstore: &'a dyn CrateStore,
+        source_span: &'a IndexVec<LocalDefId, Span>,
     ) -> Self {
         let always_ignore_spans = true;
-        Self::new_with_or_without_spans(sess, definitions, cstore, always_ignore_spans)
+        Self::new_with_or_without_spans(sess, definitions, cstore, source_span, always_ignore_spans)
     }
 
     /// Allow hashing
@@ -161,10 +162,7 @@
 
     #[inline]
     pub fn is_ignored_attr(&self, name: Symbol) -> bool {
-        thread_local! {
-            static IGNORED_ATTRIBUTES: FxHashSet<Symbol> = compute_ignored_attr_names();
-        }
-        IGNORED_ATTRIBUTES.with(|attrs| attrs.contains(&name))
+        ich::IGNORED_ATTRIBUTES.contains(&name)
     }
 
     #[inline]
@@ -198,7 +196,7 @@
 
     #[inline]
     fn def_span(&self, def_id: LocalDefId) -> Span {
-        self.definitions.def_span(def_id)
+        self.source_span[def_id]
     }
 
     #[inline]
diff --git a/compiler/rustc_query_system/src/ich/impls_syntax.rs b/compiler/rustc_query_system/src/ich/impls_syntax.rs
index acf2990..1fa0859 100644
--- a/compiler/rustc_query_system/src/ich/impls_syntax.rs
+++ b/compiler/rustc_query_system/src/ich/impls_syntax.rs
@@ -69,7 +69,7 @@
             external_src: _,
             start_pos,
             end_pos: _,
-            ref lines,
+            lines: _,
             ref multibyte_chars,
             ref non_narrow_chars,
             ref normalized_pos,
@@ -79,11 +79,15 @@
 
         src_hash.hash_stable(hcx, hasher);
 
-        // We only hash the relative position within this source_file
-        lines.len().hash_stable(hcx, hasher);
-        for &line in lines.iter() {
-            stable_byte_pos(line, start_pos).hash_stable(hcx, hasher);
-        }
+        // We are always in `Lines` form by the time we reach here.
+        assert!(self.lines.borrow().is_lines());
+        self.lines(|lines| {
+            // We only hash the relative position within this source_file
+            lines.len().hash_stable(hcx, hasher);
+            for &line in lines.iter() {
+                stable_byte_pos(line, start_pos).hash_stable(hcx, hasher);
+            }
+        });
 
         // We only hash the relative position within this source_file
         multibyte_chars.len().hash_stable(hcx, hasher);
diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs
index 3498df9..3e4c7ad 100644
--- a/compiler/rustc_query_system/src/query/plumbing.rs
+++ b/compiler/rustc_query_system/src/query/plumbing.rs
@@ -316,7 +316,7 @@
     OnHit: FnOnce(&C::Stored) -> R,
 {
     cache.lookup(&key, |value, index| {
-        if unlikely!(tcx.profiler().enabled()) {
+        if std::intrinsics::unlikely(tcx.profiler().enabled()) {
             tcx.profiler().query_cache_hit(index.into());
         }
         tcx.dep_graph().read_index(index);
@@ -354,7 +354,7 @@
                 .lookup(&key, |value, index| (value.clone(), index))
                 .unwrap_or_else(|_| panic!("value must be in cache after waiting"));
 
-            if unlikely!(tcx.dep_context().profiler().enabled()) {
+            if std::intrinsics::unlikely(tcx.dep_context().profiler().enabled()) {
                 tcx.dep_context().profiler().query_cache_hit(index.into());
             }
             query_blocked_prof_timer.finish_with_query_invocation_id(index.into());
@@ -422,7 +422,7 @@
     let diagnostics = diagnostics.into_inner();
     let side_effects = QuerySideEffects { diagnostics };
 
-    if unlikely!(!side_effects.is_empty()) {
+    if std::intrinsics::unlikely(!side_effects.is_empty()) {
         if query.anon {
             tcx.store_side_effects_for_anon_node(dep_node_index, side_effects);
         } else {
@@ -466,7 +466,9 @@
         prof_timer.finish_with_query_invocation_id(dep_node_index.into());
 
         if let Some(result) = result {
-            if unlikely!(tcx.dep_context().sess().opts.debugging_opts.query_dep_graph) {
+            if std::intrinsics::unlikely(
+                tcx.dep_context().sess().opts.debugging_opts.query_dep_graph,
+            ) {
                 dep_graph.mark_debug_loaded_from_disk(*dep_node)
             }
 
@@ -483,8 +485,8 @@
             // currently afford to verify every hash. This subset should still
             // give us some coverage of potential bugs though.
             let try_verify = prev_fingerprint.as_value().1 % 32 == 0;
-            if unlikely!(
-                try_verify || tcx.dep_context().sess().opts.debugging_opts.incremental_verify_ich
+            if std::intrinsics::unlikely(
+                try_verify || tcx.dep_context().sess().opts.debugging_opts.incremental_verify_ich,
             ) {
                 incremental_verify_ich(*tcx.dep_context(), &result, dep_node, query);
             }
@@ -723,7 +725,7 @@
     // Ensure that only one of them runs the query.
     let cache = Q::query_cache(tcx);
     let cached = cache.lookup(&key, |_, index| {
-        if unlikely!(tcx.dep_context().profiler().enabled()) {
+        if std::intrinsics::unlikely(tcx.dep_context().profiler().enabled()) {
             tcx.dep_context().profiler().query_cache_hit(index.into());
         }
     });
diff --git a/compiler/rustc_resolve/Cargo.toml b/compiler/rustc_resolve/Cargo.toml
index b2178ff..8bd8eb4 100644
--- a/compiler/rustc_resolve/Cargo.toml
+++ b/compiler/rustc_resolve/Cargo.toml
@@ -12,7 +12,6 @@
 rustc_ast = { path = "../rustc_ast" }
 rustc_arena = { path = "../rustc_arena" }
 rustc_middle = { path = "../rustc_middle" }
-rustc_ast_lowering = { path = "../rustc_ast_lowering" }
 rustc_ast_pretty = { path = "../rustc_ast_pretty" }
 rustc_attr = { path = "../rustc_attr" }
 rustc_data_structures = { path = "../rustc_data_structures" }
diff --git a/compiler/rustc_resolve/src/access_levels.rs b/compiler/rustc_resolve/src/access_levels.rs
index 61a9b64..3fba923 100644
--- a/compiler/rustc_resolve/src/access_levels.rs
+++ b/compiler/rustc_resolve/src/access_levels.rs
@@ -5,7 +5,6 @@
 use rustc_ast::EnumDef;
 use rustc_ast::ForeignMod;
 use rustc_ast::NodeId;
-use rustc_ast_lowering::ResolverAstLowering;
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::def_id::CRATE_DEF_ID;
 use rustc_middle::middle::privacy::AccessLevel;
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index dffec44..6631470 100644
--- a/compiler/rustc_resolve/src/build_reduced_graph.rs
+++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -10,24 +10,24 @@
 use crate::macros::{MacroRulesBinding, MacroRulesScope, MacroRulesScopeRef};
 use crate::Namespace::{self, MacroNS, TypeNS, ValueNS};
 use crate::{Determinacy, ExternPreludeEntry, Finalize, Module, ModuleKind, ModuleOrUniformRoot};
-use crate::{NameBinding, NameBindingKind, ParentScope, PathResult, PerNS, ResolutionError};
+use crate::{
+    MacroData, NameBinding, NameBindingKind, ParentScope, PathResult, PerNS, ResolutionError,
+};
 use crate::{Resolver, ResolverArenas, Segment, ToNameBinding, VisResolutionError};
 
 use rustc_ast::visit::{self, AssocCtxt, Visitor};
 use rustc_ast::{self as ast, AssocItem, AssocItemKind, MetaItemKind, StmtKind};
 use rustc_ast::{Block, Fn, ForeignItem, ForeignItemKind, Impl, Item, ItemKind, NodeId};
-use rustc_ast_lowering::ResolverAstLowering;
 use rustc_attr as attr;
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::{struct_span_err, Applicability};
-use rustc_expand::base::SyntaxExtension;
 use rustc_expand::expand::AstFragment;
 use rustc_hir::def::{self, *};
 use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID};
 use rustc_metadata::creader::LoadedMacro;
 use rustc_middle::bug;
 use rustc_middle::metadata::ModChild;
-use rustc_middle::ty;
+use rustc_middle::ty::{self, DefIdTree};
 use rustc_session::cstore::CrateStore;
 use rustc_span::hygiene::{ExpnId, LocalExpnId, MacroKind};
 use rustc_span::source_map::{respan, Spanned};
@@ -81,7 +81,7 @@
 impl<'a> Resolver<'a> {
     /// Defines `name` in namespace `ns` of module `parent` to be `def` if it is not yet defined;
     /// otherwise, reports an error.
-    crate fn define<T>(&mut self, parent: Module<'a>, ident: Ident, ns: Namespace, def: T)
+    pub(crate) fn define<T>(&mut self, parent: Module<'a>, ident: Ident, ns: Namespace, def: T)
     where
         T: ToNameBinding<'a>,
     {
@@ -112,10 +112,7 @@
         loop {
             match self.get_module(def_id) {
                 Some(module) => return module,
-                None => {
-                    def_id.index =
-                        self.def_key(def_id).parent.expect("non-root `DefId` without parent")
-                }
+                None => def_id = self.parent(def_id),
             }
         }
     }
@@ -127,7 +124,7 @@
     /// If `def_id` refers to a module (in resolver's sense, i.e. a module item, crate root, enum,
     /// or trait), then this function returns that module's resolver representation, otherwise it
     /// returns `None`.
-    crate fn get_module(&mut self, def_id: DefId) -> Option<Module<'a>> {
+    pub(crate) fn get_module(&mut self, def_id: DefId) -> Option<Module<'a>> {
         if let module @ Some(..) = self.module_map.get(&def_id) {
             return module.copied();
         }
@@ -162,7 +159,7 @@
         }
     }
 
-    crate fn expn_def_scope(&mut self, expn_id: ExpnId) -> Module<'a> {
+    pub(crate) fn expn_def_scope(&mut self, expn_id: ExpnId) -> Module<'a> {
         match expn_id.expn_data().macro_def_id {
             Some(def_id) => self.macro_def_scope(def_id),
             None => expn_id
@@ -172,7 +169,7 @@
         }
     }
 
-    crate fn macro_def_scope(&mut self, def_id: DefId) -> Module<'a> {
+    pub(crate) fn macro_def_scope(&mut self, def_id: DefId) -> Module<'a> {
         if let Some(id) = def_id.as_local() {
             self.local_macro_def_scopes[&id]
         } else {
@@ -180,29 +177,35 @@
         }
     }
 
-    crate fn get_macro(&mut self, res: Res) -> Option<Lrc<SyntaxExtension>> {
+    pub(crate) fn get_macro(&mut self, res: Res) -> Option<MacroData> {
         match res {
             Res::Def(DefKind::Macro(..), def_id) => Some(self.get_macro_by_def_id(def_id)),
-            Res::NonMacroAttr(_) => Some(self.non_macro_attr.clone()),
+            Res::NonMacroAttr(_) => {
+                Some(MacroData { ext: self.non_macro_attr.clone(), macro_rules: false })
+            }
             _ => None,
         }
     }
 
-    crate fn get_macro_by_def_id(&mut self, def_id: DefId) -> Lrc<SyntaxExtension> {
-        if let Some(ext) = self.macro_map.get(&def_id) {
-            return ext.clone();
+    pub(crate) fn get_macro_by_def_id(&mut self, def_id: DefId) -> MacroData {
+        if let Some(macro_data) = self.macro_map.get(&def_id) {
+            return macro_data.clone();
         }
 
-        let ext = Lrc::new(match self.cstore().load_macro_untracked(def_id, &self.session) {
-            LoadedMacro::MacroDef(item, edition) => self.compile_macro(&item, edition).0,
-            LoadedMacro::ProcMacro(ext) => ext,
-        });
+        let (ext, macro_rules) = match self.cstore().load_macro_untracked(def_id, &self.session) {
+            LoadedMacro::MacroDef(item, edition) => (
+                Lrc::new(self.compile_macro(&item, edition).0),
+                matches!(item.kind, ItemKind::MacroDef(def) if def.macro_rules),
+            ),
+            LoadedMacro::ProcMacro(extz) => (Lrc::new(extz), false),
+        };
 
-        self.macro_map.insert(def_id, ext.clone());
-        ext
+        let macro_data = MacroData { ext, macro_rules };
+        self.macro_map.insert(def_id, macro_data.clone());
+        macro_data
     }
 
-    crate fn build_reduced_graph(
+    pub(crate) fn build_reduced_graph(
         &mut self,
         fragment: &AstFragment,
         parent_scope: ParentScope<'a>,
@@ -213,7 +216,7 @@
         visitor.parent_scope.macro_rules
     }
 
-    crate fn build_reduced_graph_external(&mut self, module: Module<'a>) {
+    pub(crate) fn build_reduced_graph_external(&mut self, module: Module<'a>) {
         for child in self.cstore().module_children_untracked(module.def_id(), self.session) {
             let parent_scope = ParentScope::module(module, self);
             BuildReducedGraphVisitor { r: self, parent_scope }
@@ -249,9 +252,6 @@
         let parent_scope = &self.parent_scope;
         match vis.kind {
             ast::VisibilityKind::Public => Ok(ty::Visibility::Public),
-            ast::VisibilityKind::Crate(..) => {
-                Ok(ty::Visibility::Restricted(CRATE_DEF_ID.to_def_id()))
-            }
             ast::VisibilityKind::Inherited => {
                 Ok(match self.parent_scope.module.kind {
                     // Any inherited visibility resolved directly inside an enum or trait
@@ -1223,12 +1223,12 @@
         ident: Ident,
         def_id: LocalDefId,
         node_id: NodeId,
-        rule_spans: &[Span],
+        rule_spans: &[(usize, Span)],
     ) {
         if !ident.as_str().starts_with('_') {
             self.r.unused_macros.insert(def_id, (node_id, ident));
-            for (rule_i, rule_span) in rule_spans.iter().enumerate() {
-                self.r.unused_macro_rules.insert((def_id, rule_i), (ident, *rule_span));
+            for (rule_i, rule_span) in rule_spans.iter() {
+                self.r.unused_macro_rules.insert((def_id, *rule_i), (ident, *rule_span));
             }
         }
     }
@@ -1254,7 +1254,7 @@
         };
 
         let res = Res::Def(DefKind::Macro(ext.macro_kind()), def_id.to_def_id());
-        self.r.macro_map.insert(def_id.to_def_id(), ext);
+        self.r.macro_map.insert(def_id.to_def_id(), MacroData { ext, macro_rules });
         self.r.local_macro_def_scopes.insert(def_id, parent_scope.module);
 
         if macro_rules {
diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs
index 6503b97..f2f6f1d 100644
--- a/compiler/rustc_resolve/src/check_unused.rs
+++ b/compiler/rustc_resolve/src/check_unused.rs
@@ -30,7 +30,6 @@
 use rustc_ast as ast;
 use rustc_ast::node_id::NodeMap;
 use rustc_ast::visit::{self, Visitor};
-use rustc_ast_lowering::ResolverAstLowering;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::{pluralize, MultiSpan};
 use rustc_session::lint::builtin::{MACRO_USE_EXTERN_CRATE, UNUSED_IMPORTS};
@@ -224,7 +223,7 @@
 }
 
 impl Resolver<'_> {
-    crate fn check_unused(&mut self, krate: &ast::Crate) {
+    pub(crate) fn check_unused(&mut self, krate: &ast::Crate) {
         for import in self.potentially_unused_imports.iter() {
             match import.kind {
                 _ if import.used.get()
@@ -315,21 +314,28 @@
                 "remove the unused import"
             };
 
-            let parent_module = visitor.r.get_nearest_non_block_module(
-                visitor.r.local_def_id(unused.use_tree_id).to_def_id(),
-            );
-            let test_module_span = match module_to_string(parent_module) {
-                Some(module)
-                    if module == "test"
-                        || module == "tests"
-                        || module.starts_with("test_")
-                        || module.starts_with("tests_")
-                        || module.ends_with("_test")
-                        || module.ends_with("_tests") =>
-                {
-                    Some(parent_module.span)
+            // If we are in the `--test` mode, suppress a help that adds the `#[cfg(test)]`
+            // attribute; however, if not, suggest adding the attribute. There is no way to
+            // retrieve attributes here because we do not have a `TyCtxt` yet.
+            let test_module_span = if visitor.r.session.opts.test {
+                None
+            } else {
+                let parent_module = visitor.r.get_nearest_non_block_module(
+                    visitor.r.local_def_id(unused.use_tree_id).to_def_id(),
+                );
+                match module_to_string(parent_module) {
+                    Some(module)
+                        if module == "test"
+                            || module == "tests"
+                            || module.starts_with("test_")
+                            || module.starts_with("tests_")
+                            || module.ends_with("_test")
+                            || module.ends_with("_tests") =>
+                    {
+                        Some(parent_module.span)
+                    }
+                    _ => None,
                 }
-                _ => None,
             };
 
             visitor.r.lint_buffer.buffer_lint_with_diagnostic(
diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs
index f086110..52706fbb 100644
--- a/compiler/rustc_resolve/src/def_collector.rs
+++ b/compiler/rustc_resolve/src/def_collector.rs
@@ -2,7 +2,6 @@
 use rustc_ast::visit::{self, FnKind};
 use rustc_ast::walk_list;
 use rustc_ast::*;
-use rustc_ast_lowering::ResolverAstLowering;
 use rustc_expand::expand::AstFragment;
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::definitions::*;
@@ -11,7 +10,7 @@
 use rustc_span::Span;
 use tracing::debug;
 
-crate fn collect_definitions(
+pub(crate) fn collect_definitions(
     resolver: &mut Resolver<'_>,
     fragment: &AstFragment,
     expansion: LocalExpnId,
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index 268e2c9..86dbcba 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -10,8 +10,9 @@
 use rustc_feature::BUILTIN_ATTRIBUTES;
 use rustc_hir::def::Namespace::{self, *};
 use rustc_hir::def::{self, CtorKind, CtorOf, DefKind, NonMacroAttrKind, PerNS};
-use rustc_hir::def_id::{DefId, CRATE_DEF_ID, LOCAL_CRATE};
+use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE};
 use rustc_hir::PrimTy;
+use rustc_index::vec::IndexVec;
 use rustc_middle::bug;
 use rustc_middle::ty::DefIdTree;
 use rustc_session::lint::builtin::ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE;
@@ -41,36 +42,36 @@
 type Res = def::Res<ast::NodeId>;
 
 /// A vector of spans and replacements, a message and applicability.
-crate type Suggestion = (Vec<(Span, String)>, String, Applicability);
+pub(crate) type Suggestion = (Vec<(Span, String)>, String, Applicability);
 
 /// Potential candidate for an undeclared or out-of-scope label - contains the ident of a
 /// similarly named label and whether or not it is reachable.
-crate type LabelSuggestion = (Ident, bool);
+pub(crate) type LabelSuggestion = (Ident, bool);
 
-crate enum SuggestionTarget {
+pub(crate) enum SuggestionTarget {
     /// The target has a similar name as the name used by the programmer (probably a typo)
     SimilarlyNamed,
     /// The target is the only valid item that can be used in the corresponding context
     SingleItem,
 }
 
-crate struct TypoSuggestion {
+pub(crate) struct TypoSuggestion {
     pub candidate: Symbol,
     pub res: Res,
     pub target: SuggestionTarget,
 }
 
 impl TypoSuggestion {
-    crate fn typo_from_res(candidate: Symbol, res: Res) -> TypoSuggestion {
+    pub(crate) fn typo_from_res(candidate: Symbol, res: Res) -> TypoSuggestion {
         Self { candidate, res, target: SuggestionTarget::SimilarlyNamed }
     }
-    crate fn single_item_from_res(candidate: Symbol, res: Res) -> TypoSuggestion {
+    pub(crate) fn single_item_from_res(candidate: Symbol, res: Res) -> TypoSuggestion {
         Self { candidate, res, target: SuggestionTarget::SingleItem }
     }
 }
 
 /// A free importable items suggested in case of resolution failure.
-crate struct ImportSuggestion {
+pub(crate) struct ImportSuggestion {
     pub did: Option<DefId>,
     pub descr: &'static str,
     pub path: Path,
@@ -92,7 +93,7 @@
 }
 
 impl<'a> Resolver<'a> {
-    crate fn report_errors(&mut self, krate: &Crate) {
+    pub(crate) fn report_errors(&mut self, krate: &Crate) {
         self.report_with_use_injections(krate);
 
         for &(span_use, span_def) in &self.macro_expanded_macro_export_errors {
@@ -130,8 +131,8 @@
             };
             if !candidates.is_empty() {
                 show_candidates(
-                    &self.definitions,
-                    self.session,
+                    &self.session,
+                    &self.source_span,
                     &mut err,
                     span,
                     &candidates,
@@ -147,7 +148,7 @@
         }
     }
 
-    crate fn report_conflict<'b>(
+    pub(crate) fn report_conflict<'b>(
         &mut self,
         parent: Module<'_>,
         ident: Ident,
@@ -271,7 +272,7 @@
                 err.tool_only_span_suggestion(
                     import.use_span_with_attributes,
                     "remove unnecessary import",
-                    String::new(),
+                    "",
                     Applicability::MaybeIncorrect,
                 );
             }
@@ -396,19 +397,14 @@
         // previous imports.
         if found_closing_brace {
             if let Some(span) = extend_span_to_previous_binding(self.session, span) {
-                err.tool_only_span_suggestion(
-                    span,
-                    message,
-                    String::new(),
-                    Applicability::MaybeIncorrect,
-                );
+                err.tool_only_span_suggestion(span, message, "", Applicability::MaybeIncorrect);
             } else {
                 // Remove the entire line if we cannot extend the span back, this indicates an
                 // `issue_52891::{self}` case.
                 err.span_suggestion(
                     import.use_span_with_attributes,
                     message,
-                    String::new(),
+                    "",
                     Applicability::MaybeIncorrect,
                 );
             }
@@ -416,10 +412,10 @@
             return;
         }
 
-        err.span_suggestion(span, message, String::new(), Applicability::MachineApplicable);
+        err.span_suggestion(span, message, "", Applicability::MachineApplicable);
     }
 
-    crate fn lint_if_path_starts_with_module(
+    pub(crate) fn lint_if_path_starts_with_module(
         &mut self,
         finalize: Option<Finalize>,
         path: &[Segment],
@@ -475,7 +471,7 @@
         );
     }
 
-    crate fn add_module_candidates(
+    pub(crate) fn add_module_candidates(
         &mut self,
         module: Module<'a>,
         names: &mut Vec<TypoSuggestion>,
@@ -495,11 +491,11 @@
     ///
     /// This takes the error provided, combines it with the span and any additional spans inside the
     /// error and emits it.
-    crate fn report_error(&mut self, span: Span, resolution_error: ResolutionError<'a>) {
+    pub(crate) fn report_error(&mut self, span: Span, resolution_error: ResolutionError<'a>) {
         self.into_struct_error(span, resolution_error).emit();
     }
 
-    crate fn into_struct_error(
+    pub(crate) fn into_struct_error(
         &mut self,
         span: Span,
         resolution_error: ResolutionError<'a>,
@@ -698,8 +694,8 @@
                         err.span_help(span, &help_msg);
                     }
                     show_candidates(
-                        &self.definitions,
-                        self.session,
+                        &self.session,
+                        &self.source_span,
                         &mut err,
                         Some(span),
                         &import_suggestions,
@@ -763,7 +759,7 @@
                         err.span_suggestion(
                             span,
                             "try using similarly named label",
-                            ident.name.to_string(),
+                            ident.name,
                             Applicability::MaybeIncorrect,
                         );
                     }
@@ -796,7 +792,7 @@
                     err.span_suggestion(
                         span,
                         "consider importing the module directly",
-                        "".to_string(),
+                        "",
                         Applicability::MachineApplicable,
                     );
 
@@ -1007,7 +1003,7 @@
                         err.span_suggestion(
                             span,
                             "try using similarly named label",
-                            ident.name.to_string(),
+                            ident.name,
                             Applicability::MaybeIncorrect,
                         );
                     }
@@ -1052,7 +1048,7 @@
         }
     }
 
-    crate fn report_vis_error(
+    pub(crate) fn report_vis_error(
         &mut self,
         vis_resolution_error: VisResolutionError<'_>,
     ) -> ErrorGuaranteed {
@@ -1413,7 +1409,7 @@
     ///
     /// N.B., the method does not look into imports, but this is not a problem,
     /// since we report the definitions (thus, the de-aliased imports).
-    crate fn lookup_import_candidates<FilterFn>(
+    pub(crate) fn lookup_import_candidates<FilterFn>(
         &mut self,
         lookup_ident: Ident,
         namespace: Namespace,
@@ -1460,7 +1456,7 @@
         suggestions
     }
 
-    crate fn unresolved_macro_suggestions(
+    pub(crate) fn unresolved_macro_suggestions(
         &mut self,
         err: &mut Diagnostic,
         macro_kind: MacroKind,
@@ -1479,8 +1475,8 @@
         let import_suggestions =
             self.lookup_import_candidates(ident, Namespace::MacroNS, parent_scope, is_expected);
         show_candidates(
-            &self.definitions,
-            self.session,
+            &self.session,
+            &self.source_span,
             err,
             None,
             &import_suggestions,
@@ -1551,7 +1547,7 @@
         }
     }
 
-    crate fn add_typo_suggestion(
+    pub(crate) fn add_typo_suggestion(
         &self,
         err: &mut Diagnostic,
         suggestion: Option<TypoSuggestion>,
@@ -1618,12 +1614,7 @@
                 format!("maybe you meant this {}", suggestion.res.descr())
             }
         };
-        err.span_suggestion(
-            span,
-            &msg,
-            suggestion.candidate.to_string(),
-            Applicability::MaybeIncorrect,
-        );
+        err.span_suggestion(span, &msg, suggestion.candidate, Applicability::MaybeIncorrect);
         true
     }
 
@@ -1780,7 +1771,7 @@
         err.emit();
     }
 
-    crate fn find_similarly_named_module_or_crate(
+    pub(crate) fn find_similarly_named_module_or_crate(
         &mut self,
         ident: Symbol,
         current_module: &Module<'a>,
@@ -1807,7 +1798,7 @@
         }
     }
 
-    crate fn report_path_resolution_error(
+    pub(crate) fn report_path_resolution_error(
         &mut self,
         path: &[Segment],
         opt_ns: Option<Namespace>, // `None` indicates a module path in import
@@ -1839,9 +1830,18 @@
                     )),
                 )
             } else if self.session.edition() == Edition::Edition2015 {
-                (format!("maybe a missing crate `{}`?", ident), None)
+                (
+                    format!("maybe a missing crate `{ident}`?"),
+                    Some((
+                        vec![],
+                        format!(
+                            "consider adding `extern crate {ident}` to use the `{ident}` crate"
+                        ),
+                        Applicability::MaybeIncorrect,
+                    )),
+                )
             } else {
-                (format!("could not find `{}` in the crate root", ident), None)
+                (format!("could not find `{ident}` in the crate root"), None)
             }
         } else if i > 0 {
             let parent = path[i - 1].ident.name;
@@ -1852,7 +1852,7 @@
                     "the list of imported crates".to_owned()
                 }
                 kw::PathRoot | kw::Crate => "the crate root".to_owned(),
-                _ => format!("`{}`", parent),
+                _ => format!("`{parent}`"),
             };
 
             let mut msg = format!("could not find `{}` in {}", ident, parent);
@@ -1914,6 +1914,8 @@
                 };
             }
             (msg, None)
+        } else if ident.name == kw::SelfUpper {
+            ("`Self` is only available in impls, traits, and type definitions".to_string(), None)
         } else if ident.name.as_str().chars().next().map_or(false, |c| c.is_ascii_uppercase()) {
             // Check whether the name refers to an item in the value namespace.
             let binding = if let Some(ribs) = ribs {
@@ -2445,8 +2447,8 @@
 /// entities with that name in all crates. This method allows outputting the
 /// results of this search in a programmer-friendly way
 fn show_candidates(
-    definitions: &rustc_hir::definitions::Definitions,
     session: &Session,
+    source_span: &IndexVec<LocalDefId, Span>,
     err: &mut Diagnostic,
     // This is `None` if all placement locations are inside expansions
     use_placement_span: Option<Span>,
@@ -2526,7 +2528,7 @@
                 err.span_suggestion_verbose(
                     first.ident.span.until(last.ident.span),
                     &format!("if you import `{}`, refer to it directly", last.ident),
-                    String::new(),
+                    "",
                     Applicability::Unspecified,
                 );
             }
@@ -2556,7 +2558,7 @@
             );
 
             if let Some(local_def_id) = def_id.and_then(|did| did.as_local()) {
-                let span = definitions.def_span(local_def_id);
+                let span = source_span[local_def_id];
                 let span = session.source_map().guess_head_span(span);
                 let mut multi_span = MultiSpan::from_span(span);
                 multi_span.push_span_label(span, "not accessible".to_string());
@@ -2585,7 +2587,7 @@
             let mut spans = Vec::new();
             for (name, _, def_id, _) in &inaccessible_path_strings {
                 if let Some(local_def_id) = def_id.and_then(|did| did.as_local()) {
-                    let span = definitions.def_span(local_def_id);
+                    let span = source_span[local_def_id];
                     let span = session.source_map().guess_head_span(span);
                     spans.push((name, span));
                 } else {
@@ -2680,7 +2682,7 @@
 }
 
 /// Convert the given number into the corresponding ordinal
-crate fn ordinalize(v: usize) -> String {
+pub(crate) fn ordinalize(v: usize) -> String {
     let suffix = match ((11..=13).contains(&(v % 100)), v % 10) {
         (false, 1) => "st",
         (false, 2) => "nd",
diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs
index baaab33..0cc6d05 100644
--- a/compiler/rustc_resolve/src/ident.rs
+++ b/compiler/rustc_resolve/src/ident.rs
@@ -28,7 +28,7 @@
     /// A generic scope visitor.
     /// Visits scopes in order to resolve some identifier in them or perform other actions.
     /// If the callback returns `Some` result, we stop visiting scopes and return it.
-    crate fn visit_scopes<T>(
+    pub(crate) fn visit_scopes<T>(
         &mut self,
         scope_set: ScopeSet<'a>,
         parent_scope: &ParentScope<'a>,
@@ -241,7 +241,7 @@
                 {
                     // The macro is a proc macro derive
                     if let Some(def_id) = module.expansion.expn_data().macro_def_id {
-                        let ext = self.get_macro_by_def_id(def_id);
+                        let ext = self.get_macro_by_def_id(def_id).ext;
                         if ext.builtin_name.is_none()
                             && ext.macro_kind() == MacroKind::Derive
                             && parent.expansion.outer_expn_is_descendant_of(*ctxt)
@@ -274,7 +274,7 @@
     /// Invariant: This must only be called during main resolution, not during
     /// import resolution.
     #[tracing::instrument(level = "debug", skip(self, ribs))]
-    crate fn resolve_ident_in_lexical_scope(
+    pub(crate) fn resolve_ident_in_lexical_scope(
         &mut self,
         mut ident: Ident,
         ns: Namespace,
@@ -368,7 +368,7 @@
     /// The function is used for resolving initial segments of macro paths (e.g., `foo` in
     /// `foo::bar!(); or `foo!();`) and also for import paths on 2018 edition.
     #[tracing::instrument(level = "debug", skip(self, scope_set))]
-    crate fn early_resolve_ident_in_lexical_scope(
+    pub(crate) fn early_resolve_ident_in_lexical_scope(
         &mut self,
         orig_ident: Ident,
         scope_set: ScopeSet<'a>,
@@ -717,7 +717,7 @@
     }
 
     #[tracing::instrument(level = "debug", skip(self))]
-    crate fn maybe_resolve_ident_in_module(
+    pub(crate) fn maybe_resolve_ident_in_module(
         &mut self,
         module: ModuleOrUniformRoot<'a>,
         ident: Ident,
@@ -729,7 +729,7 @@
     }
 
     #[tracing::instrument(level = "debug", skip(self))]
-    crate fn resolve_ident_in_module(
+    pub(crate) fn resolve_ident_in_module(
         &mut self,
         module: ModuleOrUniformRoot<'a>,
         ident: Ident,
@@ -1171,6 +1171,7 @@
                         | AssocItemRibKind
                         | ModuleRibKind(..)
                         | MacroDefinition(..)
+                        | InlineAsmSymRibKind
                         | ForwardGenericParamBanRibKind => {
                             // Nothing to do. Continue.
                             continue;
@@ -1216,22 +1217,6 @@
                             }
                             return Res::Err;
                         }
-                        InlineAsmSymRibKind => {
-                            let features = self.session.features_untracked();
-                            if !features.generic_const_exprs {
-                                if let Some(span) = finalize {
-                                    self.report_error(
-                                        span,
-                                        ResolutionError::ParamInNonTrivialAnonConst {
-                                            name: rib_ident.name,
-                                            is_type: true,
-                                        },
-                                    );
-                                }
-                                return Res::Err;
-                            }
-                            continue;
-                        }
                     };
 
                     if let Some(span) = finalize {
@@ -1262,6 +1247,7 @@
                         | AssocItemRibKind
                         | ModuleRibKind(..)
                         | MacroDefinition(..)
+                        | InlineAsmSymRibKind
                         | ForwardGenericParamBanRibKind => continue,
 
                         ConstantItemRibKind(trivial, _) => {
@@ -1296,22 +1282,6 @@
                             }
                             return Res::Err;
                         }
-                        InlineAsmSymRibKind => {
-                            let features = self.session.features_untracked();
-                            if !features.generic_const_exprs {
-                                if let Some(span) = finalize {
-                                    self.report_error(
-                                        span,
-                                        ResolutionError::ParamInNonTrivialAnonConst {
-                                            name: rib_ident.name,
-                                            is_type: false,
-                                        },
-                                    );
-                                }
-                                return Res::Err;
-                            }
-                            continue;
-                        }
                     };
 
                     // This was an attempt to use a const parameter outside its scope.
@@ -1333,7 +1303,7 @@
     }
 
     #[tracing::instrument(level = "debug", skip(self))]
-    crate fn maybe_resolve_path(
+    pub(crate) fn maybe_resolve_path(
         &mut self,
         path: &[Segment],
         opt_ns: Option<Namespace>, // `None` indicates a module path in import
@@ -1343,7 +1313,7 @@
     }
 
     #[tracing::instrument(level = "debug", skip(self))]
-    crate fn resolve_path(
+    pub(crate) fn resolve_path(
         &mut self,
         path: &[Segment],
         opt_ns: Option<Namespace>, // `None` indicates a module path in import
@@ -1354,7 +1324,7 @@
         self.resolve_path_with_ribs(path, opt_ns, parent_scope, finalize, None, ignore_binding)
     }
 
-    crate fn resolve_path_with_ribs(
+    pub(crate) fn resolve_path_with_ribs(
         &mut self,
         path: &[Segment],
         opt_ns: Option<Namespace>, // `None` indicates a module path in import
@@ -1532,6 +1502,7 @@
                         return PathResult::NonModule(PartialRes::new(Res::Err));
                     } else if opt_ns.is_some() && (is_last || maybe_assoc) {
                         self.lint_if_path_starts_with_module(finalize, path, second_binding);
+                        record_segment_res(self, res);
                         return PathResult::NonModule(PartialRes::with_unresolved_segments(
                             res,
                             path.len() - i - 1,
diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs
index 3d0e2b9..c6aa57f 100644
--- a/compiler/rustc_resolve/src/imports.rs
+++ b/compiler/rustc_resolve/src/imports.rs
@@ -12,7 +12,7 @@
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::intern::Interned;
 use rustc_errors::{pluralize, struct_span_err, Applicability, MultiSpan};
-use rustc_hir::def::{self, PartialRes};
+use rustc_hir::def::{self, DefKind, PartialRes};
 use rustc_middle::metadata::ModChild;
 use rustc_middle::span_bug;
 use rustc_middle::ty;
@@ -64,7 +64,7 @@
 
 /// One import.
 #[derive(Debug, Clone)]
-crate struct Import<'a> {
+pub(crate) struct Import<'a> {
     pub kind: ImportKind<'a>,
 
     /// The ID of the `extern crate`, `UseTree` etc that imported this `Import`.
@@ -125,7 +125,7 @@
 
 /// Records information about the resolution of a name in a namespace of a module.
 #[derive(Clone, Default, Debug)]
-crate struct NameResolution<'a> {
+pub(crate) struct NameResolution<'a> {
     /// Single imports that may define the name in the namespace.
     /// Imports are arena-allocated, so it's ok to use pointers as keys.
     pub single_imports: FxHashSet<Interned<'a, Import<'a>>>,
@@ -146,7 +146,7 @@
         })
     }
 
-    crate fn add_single_import(&mut self, import: &'a Import<'a>) {
+    pub(crate) fn add_single_import(&mut self, import: &'a Import<'a>) {
         self.single_imports.insert(Interned::new_unchecked(import));
     }
 }
@@ -169,7 +169,7 @@
 impl<'a> Resolver<'a> {
     // Given a binding and an import that resolves to it,
     // return the corresponding binding defined by the import.
-    crate fn import(
+    pub(crate) fn import(
         &self,
         binding: &'a NameBinding<'a>,
         import: &'a Import<'a>,
@@ -198,7 +198,7 @@
     }
 
     // Define the name or return the existing binding if there is a collision.
-    crate fn try_define(
+    pub(crate) fn try_define(
         &mut self,
         module: Module<'a>,
         key: BindingKey,
@@ -475,6 +475,10 @@
             }
 
             if let Some((suggestions, msg, applicability)) = err.suggestion {
+                if suggestions.is_empty() {
+                    diag.help(&msg);
+                    continue;
+                }
                 diag.multipart_suggestion(&msg, suggestions, applicability);
             }
         }
@@ -918,11 +922,28 @@
                         .note(&format!("consider declaring type or module `{}` with `pub`", ident))
                         .emit();
                 } else {
-                    let note_msg =
-                        format!("consider marking `{}` as `pub` in the imported module", ident);
-                    struct_span_err!(self.r.session, import.span, E0364, "{}", error_msg)
-                        .span_note(import.span, &note_msg)
-                        .emit();
+                    let mut err =
+                        struct_span_err!(self.r.session, import.span, E0364, "{error_msg}");
+                    match binding.kind {
+                        NameBindingKind::Res(Res::Def(DefKind::Macro(_), def_id), _)
+                            // exclude decl_macro
+                            if self.r.get_macro_by_def_id(def_id).macro_rules =>
+                        {
+                            err.span_help(
+                                binding.span,
+                                "consider adding a `#[macro_export]` to the macro in the imported module",
+                            );
+                        }
+                        _ => {
+                            err.span_note(
+                                import.span,
+                                &format!(
+                                    "consider marking `{ident}` as `pub` in the imported module"
+                                ),
+                            );
+                        }
+                    }
+                    err.emit();
                 }
             }
         }
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 723e66e..ced3290 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -1,3 +1,4 @@
+// ignore-tidy-filelength
 //! "Late resolution" is the pass that resolves most of names in a crate beside imports and macros.
 //! It runs when the crate is fully expanded and its module structure is fully built.
 //! So it just walks through the crate and resolves all the expressions, types, etc.
@@ -14,15 +15,12 @@
 use rustc_ast::ptr::P;
 use rustc_ast::visit::{self, AssocCtxt, BoundKind, FnCtxt, FnKind, Visitor};
 use rustc_ast::*;
-use rustc_ast_lowering::{LifetimeRes, ResolverAstLowering};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
 use rustc_errors::DiagnosticId;
 use rustc_hir::def::Namespace::{self, *};
-use rustc_hir::def::{self, CtorKind, DefKind, PartialRes, PerNS};
-use rustc_hir::def_id::{DefId, CRATE_DEF_ID};
-use rustc_hir::definitions::DefPathData;
+use rustc_hir::def::{self, CtorKind, DefKind, LifetimeRes, PartialRes, PerNS};
+use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID};
 use rustc_hir::{PrimTy, TraitCandidate};
-use rustc_index::vec::Idx;
 use rustc_middle::ty::DefIdTree;
 use rustc_middle::{bug, span_bug};
 use rustc_session::lint;
@@ -36,7 +34,7 @@
 use tracing::debug;
 
 mod diagnostics;
-crate mod lifetimes;
+pub(crate) mod lifetimes;
 
 type Res = def::Res<NodeId>;
 
@@ -89,7 +87,7 @@
 
 /// Does this the item (from the item rib scope) allow generic parameters?
 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
-crate enum HasGenericParams {
+pub(crate) enum HasGenericParams {
     Yes,
     No,
 }
@@ -101,7 +99,7 @@
 }
 
 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
-crate enum ConstantItemKind {
+pub(crate) enum ConstantItemKind {
     Const,
     Static,
 }
@@ -109,7 +107,7 @@
 /// The rib kind restricts certain accesses,
 /// e.g. to a `Res::Local` of an outer item.
 #[derive(Copy, Clone, Debug)]
-crate enum RibKind<'a> {
+pub(crate) enum RibKind<'a> {
     /// No restriction needs to be applied.
     NormalRibKind,
 
@@ -158,7 +156,7 @@
 impl RibKind<'_> {
     /// Whether this rib kind contains generic parameters, as opposed to local
     /// variables.
-    crate fn contains_params(&self) -> bool {
+    pub(crate) fn contains_params(&self) -> bool {
         match self {
             NormalRibKind
             | ClosureOrAsyncRibKind
@@ -171,6 +169,23 @@
             AssocItemRibKind | ItemRibKind(_) | ForwardGenericParamBanRibKind => true,
         }
     }
+
+    /// This rib forbids referring to labels defined in upwards ribs.
+    fn is_label_barrier(self) -> bool {
+        match self {
+            NormalRibKind | MacroDefinition(..) => false,
+
+            AssocItemRibKind
+            | ClosureOrAsyncRibKind
+            | FnItemRibKind
+            | ItemRibKind(..)
+            | ConstantItemRibKind(..)
+            | ModuleRibKind(..)
+            | ForwardGenericParamBanRibKind
+            | ConstParamTyRibKind
+            | InlineAsmSymRibKind => true,
+        }
+    }
 }
 
 /// A single local scope.
@@ -181,12 +196,12 @@
 /// stack. This may be, for example, a `let` statement (because it introduces variables), a macro,
 /// etc.
 ///
-/// Different [rib kinds](enum.RibKind) are transparent for different names.
+/// Different [rib kinds](enum@RibKind) are transparent for different names.
 ///
 /// The resolution keeps a separate stack of ribs as it traverses the AST for each namespace. When
 /// resolving, the name is looked up from inside out.
 #[derive(Debug)]
-crate struct Rib<'a, R = Res> {
+pub(crate) struct Rib<'a, R = Res> {
     pub bindings: IdentMap<R>,
     pub kind: RibKind<'a>,
 }
@@ -197,13 +212,19 @@
     }
 }
 
+#[derive(Clone, Copy, Debug)]
+enum LifetimeUseSet {
+    One { use_span: Span, use_ctxt: visit::LifetimeCtxt },
+    Many,
+}
+
 #[derive(Copy, Clone, Debug)]
 enum LifetimeRibKind {
     /// This rib acts as a barrier to forbid reference to lifetimes of a parent item.
     Item,
 
     /// This rib declares generic parameters.
-    Generics { parent: NodeId, span: Span, kind: LifetimeBinderKind },
+    Generics { binder: NodeId, span: Span, kind: LifetimeBinderKind },
 
     /// FIXME(const_generics): This patches over an ICE caused by non-'static lifetimes in const
     /// generics. We are disallowing this until we can decide on how we want to handle non-'static
@@ -215,14 +236,21 @@
     /// `body_id` is an anonymous constant and `lifetime_ref` is non-static.
     AnonConst,
 
-    /// For **Modern** cases, create a new anonymous region parameter
-    /// and reference that.
+    /// Create a new anonymous lifetime parameter and reference it.
     ///
-    /// For **Dyn Bound** cases, pass responsibility to
-    /// `resolve_lifetime` code.
+    /// If `report_in_path`, report an error when encountering lifetime elision in a path:
+    /// ```compile_fail
+    /// struct Foo<'a> { x: &'a () }
+    /// async fn foo(x: Foo) {}
+    /// ```
     ///
-    /// For **Deprecated** cases, report an error.
-    AnonymousCreateParameter(NodeId),
+    /// Note: the error should not trigger when the elided lifetime is in a pattern or
+    /// expression-position path:
+    /// ```
+    /// struct Foo<'a> { x: &'a () }
+    /// async fn foo(Foo { x: _ }: Foo<'_>) {}
+    /// ```
+    AnonymousCreateParameter { binder: NodeId, report_in_path: bool },
 
     /// Give a hard error when either `&` or `'_` is written. Used to
     /// rule out things like `where T: Foo<'_>`. Does not imply an
@@ -230,7 +258,7 @@
     AnonymousReportError,
 
     /// Pass responsibility to `resolve_lifetime` code for all cases.
-    AnonymousPassThrough(NodeId),
+    AnonymousPassThrough(NodeId, /* in_fn_return */ bool),
 }
 
 #[derive(Copy, Clone, Debug)]
@@ -271,13 +299,13 @@
 }
 
 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
-crate enum AliasPossibility {
+pub(crate) enum AliasPossibility {
     No,
     Maybe,
 }
 
 #[derive(Copy, Clone, Debug)]
-crate enum PathSource<'a> {
+pub(crate) enum PathSource<'a> {
     // Type paths `Path`.
     Type,
     // Trait paths in bounds or impls.
@@ -359,7 +387,7 @@
         matches!(self, PathSource::Expr(Some(&Expr { kind: ExprKind::Call(..), .. })))
     }
 
-    crate fn is_expected(self, res: Res) -> bool {
+    pub(crate) fn is_expected(self, res: Res) -> bool {
         match self {
             PathSource::Type => matches!(
                 res,
@@ -489,6 +517,9 @@
 
     /// The current impl items (used to suggest).
     current_impl_items: Option<&'ast [P<AssocItem>]>,
+
+    /// When processing impl trait
+    currently_processing_impl_trait: Option<(TraitRef, Ty)>,
 }
 
 struct LateResolutionVisitor<'a, 'b, 'ast> {
@@ -519,6 +550,9 @@
     /// In most cases this will be `None`, in which case errors will always be reported.
     /// If it is `true`, then it will be updated when entering a nested function or trait body.
     in_func_body: bool,
+
+    /// Count the number of places a lifetime is used.
+    lifetime_uses: FxHashMap<LocalDefId, LifetimeUseSet>,
 }
 
 /// Walks the whole crate in DFS order, visiting each item, resolving names as it goes.
@@ -577,6 +611,30 @@
             TyKind::Path(ref qself, ref path) => {
                 self.diagnostic_metadata.current_type_path = Some(ty);
                 self.smart_resolve_path(ty.id, qself.as_ref(), path, PathSource::Type);
+
+                // Check whether we should interpret this as a bare trait object.
+                if qself.is_none()
+                    && let Some(partial_res) = self.r.partial_res_map.get(&ty.id)
+                    && partial_res.unresolved_segments() == 0
+                    && let Res::Def(DefKind::Trait | DefKind::TraitAlias, _) = partial_res.base_res()
+                {
+                    // This path is actually a bare trait object.  In case of a bare `Fn`-trait
+                    // object with anonymous lifetimes, we need this rib to correctly place the
+                    // synthetic lifetimes.
+                    let span = ty.span.shrink_to_lo().to(path.span.shrink_to_lo());
+                    self.with_generic_param_rib(
+                        &[],
+                        NormalRibKind,
+                        LifetimeRibKind::Generics {
+                            binder: ty.id,
+                            kind: LifetimeBinderKind::PolyTrait,
+                            span,
+                        },
+                        |this| this.visit_path(&path, ty.id),
+                    );
+                    self.diagnostic_metadata.current_type_path = prev_ty;
+                    return;
+                }
             }
             TyKind::ImplicitSelf => {
                 let self_ty = Ident::with_dummy_span(kw::SelfUpper);
@@ -594,26 +652,27 @@
                 self.diagnostic_metadata.current_trait_object = Some(&bounds[..]);
             }
             TyKind::BareFn(ref bare_fn) => {
-                let span = if bare_fn.generic_params.is_empty() {
-                    ty.span.shrink_to_lo()
-                } else {
-                    ty.span
-                };
+                let span = ty.span.shrink_to_lo().to(bare_fn.decl_span.shrink_to_lo());
                 self.with_generic_param_rib(
                     &bare_fn.generic_params,
                     NormalRibKind,
                     LifetimeRibKind::Generics {
-                        parent: ty.id,
+                        binder: ty.id,
                         kind: LifetimeBinderKind::BareFnType,
                         span,
                     },
                     |this| {
+                        this.visit_generic_params(&bare_fn.generic_params, false);
                         this.with_lifetime_rib(
-                            LifetimeRibKind::AnonymousPassThrough(ty.id),
-                            |this| {
-                                this.visit_generic_param_vec(&bare_fn.generic_params, false);
-                                visit::walk_fn_decl(this, &bare_fn.decl);
+                            LifetimeRibKind::AnonymousCreateParameter {
+                                binder: ty.id,
+                                report_in_path: false,
                             },
+                            |this| walk_list!(this, visit_param, &bare_fn.decl.inputs),
+                        );
+                        this.with_lifetime_rib(
+                            LifetimeRibKind::AnonymousPassThrough(ty.id, true),
+                            |this| this.visit_fn_ret_ty(&bare_fn.decl.output),
                         );
                     },
                 );
@@ -627,18 +686,17 @@
         self.diagnostic_metadata.current_type_path = prev_ty;
     }
     fn visit_poly_trait_ref(&mut self, tref: &'ast PolyTraitRef, _: &'ast TraitBoundModifier) {
-        let span =
-            if tref.bound_generic_params.is_empty() { tref.span.shrink_to_lo() } else { tref.span };
+        let span = tref.span.shrink_to_lo().to(tref.trait_ref.path.span.shrink_to_lo());
         self.with_generic_param_rib(
             &tref.bound_generic_params,
             NormalRibKind,
             LifetimeRibKind::Generics {
-                parent: tref.trait_ref.ref_id,
+                binder: tref.trait_ref.ref_id,
                 kind: LifetimeBinderKind::PolyTrait,
                 span,
             },
             |this| {
-                this.visit_generic_param_vec(&tref.bound_generic_params, false);
+                this.visit_generic_params(&tref.bound_generic_params, false);
                 this.smart_resolve_path(
                     tref.trait_ref.ref_id,
                     None,
@@ -657,7 +715,7 @@
                         &generics.params,
                         ItemRibKind(HasGenericParams::Yes),
                         LifetimeRibKind::Generics {
-                            parent: foreign_item.id,
+                            binder: foreign_item.id,
                             kind: LifetimeBinderKind::Item,
                             span: generics.span,
                         },
@@ -671,7 +729,7 @@
                         &generics.params,
                         ItemRibKind(HasGenericParams::Yes),
                         LifetimeRibKind::Generics {
-                            parent: foreign_item.id,
+                            binder: foreign_item.id,
                             kind: LifetimeBinderKind::Function,
                             span: generics.span,
                         },
@@ -695,13 +753,18 @@
             // a body, or if there's no body for some other reason.
             FnKind::Fn(FnCtxt::Foreign, _, sig, _, generics, _)
             | FnKind::Fn(_, _, sig, _, generics, None) => {
-                self.with_lifetime_rib(LifetimeRibKind::AnonymousPassThrough(fn_id), |this| {
-                    // We don't need to deal with patterns in parameters, because
-                    // they are not possible for foreign or bodiless functions.
-                    this.visit_fn_header(&sig.header);
-                    this.visit_generics(generics);
-                    visit::walk_fn_decl(this, &sig.decl);
-                });
+                self.visit_fn_header(&sig.header);
+                self.visit_generics(generics);
+                // We don't need to deal with patterns in parameters, because
+                // they are not possible for foreign or bodiless functions.
+                self.with_lifetime_rib(
+                    LifetimeRibKind::AnonymousPassThrough(fn_id, false),
+                    |this| walk_list!(this, visit_param, &sig.decl.inputs),
+                );
+                self.with_lifetime_rib(
+                    LifetimeRibKind::AnonymousPassThrough(fn_id, true),
+                    |this| this.visit_fn_ret_ty(&sig.decl.output),
+                );
                 return;
             }
             FnKind::Fn(FnCtxt::Free, ..) => FnItemRibKind,
@@ -713,92 +776,137 @@
             self.diagnostic_metadata.current_function = Some((fn_kind, sp));
         }
         debug!("(resolving function) entering function");
-        let declaration = fn_kind.decl();
 
         // Create a value rib for the function.
         self.with_rib(ValueNS, rib_kind, |this| {
             // Create a label rib for the function.
-            this.with_label_rib(rib_kind, |this| {
-                let async_node_id = fn_kind.header().and_then(|h| h.asyncness.opt_return_id());
+            this.with_label_rib(FnItemRibKind, |this| {
+                match fn_kind {
+                    FnKind::Fn(_, _, sig, _, generics, body) => {
+                        this.visit_generics(generics);
 
-                if let FnKind::Fn(_, _, _, _, generics, _) = fn_kind {
-                    this.visit_generics(generics);
-                }
+                        let declaration = &sig.decl;
+                        let async_node_id = sig.header.asyncness.opt_return_id();
 
-                if let Some(async_node_id) = async_node_id {
-                    // In `async fn`, argument-position elided lifetimes
-                    // must be transformed into fresh generic parameters so that
-                    // they can be applied to the opaque `impl Trait` return type.
-                    this.with_lifetime_rib(
-                        LifetimeRibKind::AnonymousCreateParameter(fn_id),
-                        |this| {
+                        // Argument-position elided lifetimes must be transformed into fresh
+                        // generic parameters.  This is especially useful for `async fn`, where
+                        // these fresh generic parameters can be applied to the opaque `impl Trait`
+                        // return type.
+                        let rib = if async_node_id.is_some() {
+                            // Only emit a hard error for `async fn`, since this kind of
+                            // elision has always been allowed in regular `fn`s.
+                            LifetimeRibKind::AnonymousCreateParameter {
+                                binder: fn_id,
+                                report_in_path: true,
+                            }
+                        } else {
+                            LifetimeRibKind::AnonymousPassThrough(fn_id, false)
+                        };
+                        this.with_lifetime_rib(
+                            rib,
                             // Add each argument to the rib.
-                            this.resolve_params(&declaration.inputs)
-                        },
-                    );
-
-                    // Construct the list of in-scope lifetime parameters for async lowering.
-                    // We include all lifetime parameters, either named or "Fresh".
-                    // The order of those parameters does not matter, as long as it is
-                    // deterministic.
-                    let mut extra_lifetime_params =
-                        this.r.extra_lifetime_params_map.get(&fn_id).cloned().unwrap_or_default();
-                    for rib in this.lifetime_ribs.iter().rev() {
-                        extra_lifetime_params.extend(
-                            rib.bindings
-                                .iter()
-                                .map(|(&ident, &(node_id, res))| (ident, node_id, res)),
+                            |this| this.resolve_params(&declaration.inputs),
                         );
-                        match rib.kind {
-                            LifetimeRibKind::Item => break,
-                            LifetimeRibKind::AnonymousCreateParameter(id) => {
-                                if let Some(earlier_fresh) =
-                                    this.r.extra_lifetime_params_map.get(&id)
-                                {
-                                    extra_lifetime_params.extend(earlier_fresh);
+
+                        // Construct the list of in-scope lifetime parameters for async lowering.
+                        // We include all lifetime parameters, either named or "Fresh".
+                        // The order of those parameters does not matter, as long as it is
+                        // deterministic.
+                        if let Some(async_node_id) = async_node_id {
+                            let mut extra_lifetime_params = this
+                                .r
+                                .extra_lifetime_params_map
+                                .get(&fn_id)
+                                .cloned()
+                                .unwrap_or_default();
+                            for rib in this.lifetime_ribs.iter().rev() {
+                                extra_lifetime_params.extend(
+                                    rib.bindings
+                                        .iter()
+                                        .map(|(&ident, &(node_id, res))| (ident, node_id, res)),
+                                );
+                                match rib.kind {
+                                    LifetimeRibKind::Item => break,
+                                    LifetimeRibKind::AnonymousCreateParameter {
+                                        binder, ..
+                                    } => {
+                                        if let Some(earlier_fresh) =
+                                            this.r.extra_lifetime_params_map.get(&binder)
+                                        {
+                                            extra_lifetime_params.extend(earlier_fresh);
+                                        }
+                                    }
+                                    _ => {}
                                 }
                             }
-                            _ => {}
+                            this.r
+                                .extra_lifetime_params_map
+                                .insert(async_node_id, extra_lifetime_params);
+                        }
+
+                        this.with_lifetime_rib(
+                            LifetimeRibKind::AnonymousPassThrough(
+                                // For async fn, the return type appears inside a custom
+                                // `impl Future` RPIT, so we override the binder's id.
+                                async_node_id.unwrap_or(fn_id),
+                                true,
+                            ),
+                            |this| visit::walk_fn_ret_ty(this, &declaration.output),
+                        );
+
+                        if let Some(body) = body {
+                            // Ignore errors in function bodies if this is rustdoc
+                            // Be sure not to set this until the function signature has been resolved.
+                            let previous_state = replace(&mut this.in_func_body, true);
+                            // Resolve the function body, potentially inside the body of an async closure
+                            this.with_lifetime_rib(
+                                LifetimeRibKind::AnonymousPassThrough(fn_id, false),
+                                |this| this.visit_block(body),
+                            );
+
+                            debug!("(resolving function) leaving function");
+                            this.in_func_body = previous_state;
                         }
                     }
-                    this.r.extra_lifetime_params_map.insert(async_node_id, extra_lifetime_params);
+                    FnKind::Closure(declaration, body) => {
+                        // We do not have any explicit generic lifetime parameter.
+                        // FIXME(rfc3216): Change when implementing `for<>` bounds on closures.
+                        this.with_lifetime_rib(
+                            LifetimeRibKind::AnonymousCreateParameter {
+                                binder: fn_id,
+                                report_in_path: false,
+                            },
+                            // Add each argument to the rib.
+                            |this| this.resolve_params(&declaration.inputs),
+                        );
+                        this.with_lifetime_rib(
+                            LifetimeRibKind::AnonymousPassThrough(fn_id, true),
+                            |this| visit::walk_fn_ret_ty(this, &declaration.output),
+                        );
 
-                    this.with_lifetime_rib(
-                        LifetimeRibKind::AnonymousPassThrough(async_node_id),
-                        |this| visit::walk_fn_ret_ty(this, &declaration.output),
-                    );
-                } else {
-                    this.with_lifetime_rib(LifetimeRibKind::AnonymousPassThrough(fn_id), |this| {
-                        // Add each argument to the rib.
-                        this.resolve_params(&declaration.inputs);
+                        // Ignore errors in function bodies if this is rustdoc
+                        // Be sure not to set this until the function signature has been resolved.
+                        let previous_state = replace(&mut this.in_func_body, true);
+                        // Resolve the function body, potentially inside the body of an async closure
+                        this.with_lifetime_rib(
+                            LifetimeRibKind::AnonymousPassThrough(fn_id, false),
+                            |this| this.visit_expr(body),
+                        );
 
-                        visit::walk_fn_ret_ty(this, &declaration.output);
-                    });
-                };
-
-                // Ignore errors in function bodies if this is rustdoc
-                // Be sure not to set this until the function signature has been resolved.
-                let previous_state = replace(&mut this.in_func_body, true);
-                // Resolve the function body, potentially inside the body of an async closure
-                this.with_lifetime_rib(LifetimeRibKind::AnonymousPassThrough(fn_id), |this| {
-                    match fn_kind {
-                        FnKind::Fn(.., body) => walk_list!(this, visit_block, body),
-                        FnKind::Closure(_, body) => this.visit_expr(body),
+                        debug!("(resolving function) leaving function");
+                        this.in_func_body = previous_state;
                     }
-                });
-
-                debug!("(resolving function) leaving function");
-                this.in_func_body = previous_state;
+                }
             })
         });
         self.diagnostic_metadata.current_function = previous_value;
     }
-    fn visit_lifetime(&mut self, lifetime: &'ast Lifetime) {
-        self.resolve_lifetime(lifetime)
+    fn visit_lifetime(&mut self, lifetime: &'ast Lifetime, use_ctxt: visit::LifetimeCtxt) {
+        self.resolve_lifetime(lifetime, use_ctxt)
     }
 
     fn visit_generics(&mut self, generics: &'ast Generics) {
-        self.visit_generic_param_vec(
+        self.visit_generic_params(
             &generics.params,
             self.diagnostic_metadata.current_self_item.is_some(),
         );
@@ -859,20 +967,73 @@
 
                 self.visit_ty(ty);
             }
-            GenericArg::Lifetime(lt) => self.visit_lifetime(lt),
+            GenericArg::Lifetime(lt) => self.visit_lifetime(lt, visit::LifetimeCtxt::GenericArg),
             GenericArg::Const(ct) => self.visit_anon_const(ct),
         }
         self.diagnostic_metadata.currently_processing_generics = prev;
     }
 
+    fn visit_assoc_constraint(&mut self, constraint: &'ast AssocConstraint) {
+        self.visit_ident(constraint.ident);
+        if let Some(ref gen_args) = constraint.gen_args {
+            // Forbid anonymous lifetimes in GAT parameters until proper semantics are decided.
+            self.with_lifetime_rib(LifetimeRibKind::AnonymousReportError, |this| {
+                this.visit_generic_args(gen_args.span(), gen_args)
+            });
+        }
+        match constraint.kind {
+            AssocConstraintKind::Equality { ref term } => match term {
+                Term::Ty(ty) => self.visit_ty(ty),
+                Term::Const(c) => self.visit_anon_const(c),
+            },
+            AssocConstraintKind::Bound { ref bounds } => {
+                walk_list!(self, visit_param_bound, bounds, BoundKind::Bound);
+            }
+        }
+    }
+
     fn visit_path_segment(&mut self, path_span: Span, path_segment: &'ast PathSegment) {
         if let Some(ref args) = path_segment.args {
             match &**args {
                 GenericArgs::AngleBracketed(..) => visit::walk_generic_args(self, path_span, args),
-                GenericArgs::Parenthesized(..) => self.with_lifetime_rib(
-                    LifetimeRibKind::AnonymousPassThrough(path_segment.id),
-                    |this| visit::walk_generic_args(this, path_span, args),
-                ),
+                GenericArgs::Parenthesized(p_args) => {
+                    // Probe the lifetime ribs to know how to behave.
+                    for rib in self.lifetime_ribs.iter().rev() {
+                        match rib.kind {
+                            // We are inside a `PolyTraitRef`.  The lifetimes are
+                            // to be intoduced in that (maybe implicit) `for<>` binder.
+                            LifetimeRibKind::Generics {
+                                binder,
+                                kind: LifetimeBinderKind::PolyTrait,
+                                ..
+                            } => {
+                                self.with_lifetime_rib(
+                                    LifetimeRibKind::AnonymousCreateParameter {
+                                        binder,
+                                        report_in_path: false,
+                                    },
+                                    |this| walk_list!(this, visit_ty, &p_args.inputs),
+                                );
+                                self.with_lifetime_rib(
+                                    LifetimeRibKind::AnonymousPassThrough(binder, true),
+                                    |this| visit::walk_fn_ret_ty(this, &p_args.output),
+                                );
+                                break;
+                            }
+                            // We have nowhere to introduce generics.  Code is malformed,
+                            // so use regular lifetime resolution to avoid spurious errors.
+                            LifetimeRibKind::Item | LifetimeRibKind::Generics { .. } => {
+                                visit::walk_generic_args(self, path_span, args);
+                                break;
+                            }
+                            LifetimeRibKind::AnonymousPassThrough(..)
+                            | LifetimeRibKind::AnonymousCreateParameter { .. }
+                            | LifetimeRibKind::AnonymousReportError
+                            | LifetimeRibKind::AnonConst
+                            | LifetimeRibKind::ConstGeneric => {}
+                        }
+                    }
+                }
             }
         }
     }
@@ -890,21 +1051,17 @@
                 ..
             }) = p
             {
-                let span = if bound_generic_params.is_empty() {
-                    predicate_span.shrink_to_lo()
-                } else {
-                    *predicate_span
-                };
+                let span = predicate_span.shrink_to_lo().to(bounded_ty.span.shrink_to_lo());
                 this.with_generic_param_rib(
                     &bound_generic_params,
                     NormalRibKind,
                     LifetimeRibKind::Generics {
-                        parent: bounded_ty.id,
+                        binder: bounded_ty.id,
                         kind: LifetimeBinderKind::WhereBound,
                         span,
                     },
                     |this| {
-                        this.visit_generic_param_vec(&bound_generic_params, false);
+                        this.visit_generic_params(&bound_generic_params, false);
                         this.visit_ty(bounded_ty);
                         for bound in bounds {
                             this.visit_param_bound(bound, BoundKind::Bound)
@@ -918,6 +1075,29 @@
         self.diagnostic_metadata.current_where_predicate = previous_value;
     }
 
+    fn visit_inline_asm(&mut self, asm: &'ast InlineAsm) {
+        for (op, _) in &asm.operands {
+            match op {
+                InlineAsmOperand::In { expr, .. }
+                | InlineAsmOperand::Out { expr: Some(expr), .. }
+                | InlineAsmOperand::InOut { expr, .. } => self.visit_expr(expr),
+                InlineAsmOperand::Out { expr: None, .. } => {}
+                InlineAsmOperand::SplitInOut { in_expr, out_expr, .. } => {
+                    self.visit_expr(in_expr);
+                    if let Some(out_expr) = out_expr {
+                        self.visit_expr(out_expr);
+                    }
+                }
+                InlineAsmOperand::Const { anon_const, .. } => {
+                    // Although this is `DefKind::AnonConst`, it is allowed to reference outer
+                    // generic parameters like an inline const.
+                    self.resolve_inline_const(anon_const);
+                }
+                InlineAsmOperand::Sym { sym } => self.visit_inline_asm_sym(sym),
+            }
+        }
+    }
+
     fn visit_inline_asm_sym(&mut self, sym: &'ast InlineAsmSym) {
         // This is similar to the code for AnonConst.
         self.with_rib(ValueNS, InlineAsmSymRibKind, |this| {
@@ -957,6 +1137,7 @@
             diagnostic_metadata: DiagnosticMetadata::default(),
             // errors at module scope should always be reported
             in_func_body: false,
+            lifetime_uses: Default::default(),
         }
     }
 
@@ -1055,7 +1236,7 @@
         }
     }
 
-    fn visit_generic_param_vec(&mut self, params: &'ast Vec<GenericParam>, add_self_upper: bool) {
+    fn visit_generic_params(&mut self, params: &'ast [GenericParam], add_self_upper: bool) {
         // For type parameter defaults, we have to ban access
         // to following type parameters, as the InternalSubsts can only
         // provide previous type parameters as they're built. We
@@ -1164,7 +1345,7 @@
     }
 
     #[tracing::instrument(level = "debug", skip(self))]
-    fn resolve_lifetime(&mut self, lifetime: &'ast Lifetime) {
+    fn resolve_lifetime(&mut self, lifetime: &'ast Lifetime, use_ctxt: visit::LifetimeCtxt) {
         let ident = lifetime.ident;
 
         if ident.name == kw::StaticLifetime {
@@ -1180,8 +1361,44 @@
         for i in &mut indices {
             let rib = &self.lifetime_ribs[i];
             let normalized_ident = ident.normalize_to_macros_2_0();
-            if let Some(&(_, region)) = rib.bindings.get(&normalized_ident) {
-                self.record_lifetime_res(lifetime.id, region);
+            if let Some(&(_, res)) = rib.bindings.get(&normalized_ident) {
+                self.record_lifetime_res(lifetime.id, res);
+
+                if let LifetimeRes::Param { param, .. } = res {
+                    match self.lifetime_uses.entry(param) {
+                        Entry::Vacant(v) => {
+                            debug!("First use of {:?} at {:?}", res, ident.span);
+                            let use_set = self
+                                .lifetime_ribs
+                                .iter()
+                                .rev()
+                                .find_map(|rib| match rib.kind {
+                                    // Do not suggest eliding a lifetime where an anonymous
+                                    // lifetime would be illegal.
+                                    LifetimeRibKind::Item
+                                    | LifetimeRibKind::AnonymousPassThrough(_, true)
+                                    | LifetimeRibKind::AnonymousReportError => {
+                                        Some(LifetimeUseSet::Many)
+                                    }
+                                    // An anonymous lifetime is legal here, go ahead.
+                                    LifetimeRibKind::AnonymousPassThrough(_, false)
+                                    | LifetimeRibKind::AnonymousCreateParameter { .. } => {
+                                        Some(LifetimeUseSet::One { use_span: ident.span, use_ctxt })
+                                    }
+                                    LifetimeRibKind::Generics { .. }
+                                    | LifetimeRibKind::ConstGeneric
+                                    | LifetimeRibKind::AnonConst => None,
+                                })
+                                .unwrap_or(LifetimeUseSet::Many);
+                            debug!(?use_ctxt, ?use_set);
+                            v.insert(use_set);
+                        }
+                        Entry::Occupied(mut o) => {
+                            debug!("Many uses of {:?} at {:?}", res, ident.span);
+                            *o.get_mut() = LifetimeUseSet::Many;
+                        }
+                    }
+                }
                 return;
             }
 
@@ -1222,8 +1439,9 @@
         for i in (0..self.lifetime_ribs.len()).rev() {
             let rib = &mut self.lifetime_ribs[i];
             match rib.kind {
-                LifetimeRibKind::AnonymousCreateParameter(item_node_id) => {
-                    self.create_fresh_lifetime(lifetime.id, lifetime.ident, item_node_id);
+                LifetimeRibKind::AnonymousCreateParameter { binder, .. } => {
+                    let res = self.create_fresh_lifetime(lifetime.id, lifetime.ident, binder);
+                    self.record_lifetime_res(lifetime.id, res);
                     return;
                 }
                 LifetimeRibKind::AnonymousReportError => {
@@ -1248,7 +1466,7 @@
                     self.record_lifetime_res(lifetime.id, LifetimeRes::Error);
                     return;
                 }
-                LifetimeRibKind::AnonymousPassThrough(node_id) => {
+                LifetimeRibKind::AnonymousPassThrough(node_id, _) => {
                     self.record_lifetime_res(
                         lifetime.id,
                         LifetimeRes::Anonymous { binder: node_id, elided },
@@ -1256,7 +1474,9 @@
                     return;
                 }
                 LifetimeRibKind::Item => break,
-                _ => {}
+                LifetimeRibKind::Generics { .. }
+                | LifetimeRibKind::ConstGeneric
+                | LifetimeRibKind::AnonConst => {}
             }
         }
         // This resolution is wrong, it passes the work to HIR lifetime resolution.
@@ -1280,27 +1500,21 @@
     }
 
     #[tracing::instrument(level = "debug", skip(self))]
-    fn create_fresh_lifetime(&mut self, id: NodeId, ident: Ident, item_node_id: NodeId) {
+    fn create_fresh_lifetime(&mut self, id: NodeId, ident: Ident, binder: NodeId) -> LifetimeRes {
         debug_assert_eq!(ident.name, kw::UnderscoreLifetime);
         debug!(?ident.span);
-        let item_def_id = self.r.local_def_id(item_node_id);
-        let def_node_id = self.r.next_node_id();
-        let def_id = self.r.create_def(
-            item_def_id,
-            def_node_id,
-            DefPathData::LifetimeNs(kw::UnderscoreLifetime),
-            self.parent_scope.expansion.to_expn_id(),
-            ident.span,
-        );
-        debug!(?def_id);
 
-        let region = LifetimeRes::Fresh { param: def_id, binder: item_node_id };
-        self.record_lifetime_res(id, region);
-        self.r.extra_lifetime_params_map.entry(item_node_id).or_insert_with(Vec::new).push((
-            ident,
-            def_node_id,
-            region,
-        ));
+        // Leave the responsibility to create the `LocalDefId` to lowering.
+        let param = self.r.next_node_id();
+        let res = LifetimeRes::Fresh { param, binder };
+
+        // Record the created lifetime parameter so lowering can pick it up and add it to HIR.
+        self.r
+            .extra_lifetime_params_map
+            .entry(binder)
+            .or_insert_with(Vec::new)
+            .push((ident, param, res));
+        res
     }
 
     #[tracing::instrument(level = "debug", skip(self))]
@@ -1350,52 +1564,6 @@
                 | PathSource::Struct
                 | PathSource::TupleStruct(..) => false,
             };
-            let mut res = LifetimeRes::Error;
-            for rib in self.lifetime_ribs.iter().rev() {
-                match rib.kind {
-                    // In create-parameter mode we error here because we don't want to support
-                    // deprecated impl elision in new features like impl elision and `async fn`,
-                    // both of which work using the `CreateParameter` mode:
-                    //
-                    //     impl Foo for std::cell::Ref<u32> // note lack of '_
-                    //     async fn foo(_: std::cell::Ref<u32>) { ... }
-                    LifetimeRibKind::AnonymousCreateParameter(_) => {
-                        break;
-                    }
-                    // `PassThrough` is the normal case.
-                    // `new_error_lifetime`, which would usually be used in the case of `ReportError`,
-                    // is unsuitable here, as these can occur from missing lifetime parameters in a
-                    // `PathSegment`, for which there is no associated `'_` or `&T` with no explicit
-                    // lifetime. Instead, we simply create an implicit lifetime, which will be checked
-                    // later, at which point a suitable error will be emitted.
-                    LifetimeRibKind::AnonymousPassThrough(binder) => {
-                        res = LifetimeRes::Anonymous { binder, elided: true };
-                        break;
-                    }
-                    LifetimeRibKind::AnonymousReportError | LifetimeRibKind::Item => {
-                        // FIXME(cjgillot) This resolution is wrong, but this does not matter
-                        // since these cases are erroneous anyway.  Lifetime resolution should
-                        // emit a "missing lifetime specifier" diagnostic.
-                        res = LifetimeRes::Anonymous { binder: DUMMY_NODE_ID, elided: true };
-                        break;
-                    }
-                    _ => {}
-                }
-            }
-
-            let node_ids = self.r.next_node_ids(expected_lifetimes);
-            self.record_lifetime_res(
-                segment_id,
-                LifetimeRes::ElidedAnchor { start: node_ids.start, end: node_ids.end },
-            );
-            for i in 0..expected_lifetimes {
-                let id = node_ids.start.plus(i);
-                self.record_lifetime_res(id, res);
-            }
-
-            if !missing {
-                continue;
-            }
 
             let elided_lifetime_span = if segment.has_generic_args {
                 // If there are brackets, but not generic arguments, then use the opening bracket
@@ -1406,25 +1574,120 @@
                 // originating from macros, since the segment's span might be from a macro arg.
                 segment.ident.span.find_ancestor_inside(path_span).unwrap_or(path_span)
             };
-            if let LifetimeRes::Error = res {
-                let sess = self.r.session;
-                let mut err = rustc_errors::struct_span_err!(
-                    sess,
-                    path_span,
-                    E0726,
-                    "implicit elided lifetime not allowed here"
-                );
-                rustc_errors::add_elided_lifetime_in_path_suggestion(
-                    sess.source_map(),
-                    &mut err,
-                    expected_lifetimes,
-                    path_span,
-                    !segment.has_generic_args,
-                    elided_lifetime_span,
-                );
-                err.note("assuming a `'static` lifetime...");
-                err.emit();
-            } else {
+            let ident = Ident::new(kw::UnderscoreLifetime, elided_lifetime_span);
+
+            let node_ids = self.r.next_node_ids(expected_lifetimes);
+            self.record_lifetime_res(
+                segment_id,
+                LifetimeRes::ElidedAnchor { start: node_ids.start, end: node_ids.end },
+            );
+
+            if !missing {
+                // Do not create a parameter for patterns and expressions.
+                for rib in self.lifetime_ribs.iter().rev() {
+                    match rib.kind {
+                        LifetimeRibKind::AnonymousPassThrough(binder, _) => {
+                            let res = LifetimeRes::Anonymous { binder, elided: true };
+                            for id in node_ids {
+                                self.record_lifetime_res(id, res);
+                            }
+                            break;
+                        }
+                        // `LifetimeRes::Error`, which would usually be used in the case of
+                        // `ReportError`, is unsuitable here, as we don't emit an error yet.  Instead,
+                        // we simply resolve to an implicit lifetime, which will be checked later, at
+                        // which point a suitable error will be emitted.
+                        LifetimeRibKind::AnonymousReportError | LifetimeRibKind::Item => {
+                            // FIXME(cjgillot) This resolution is wrong, but this does not matter
+                            // since these cases are erroneous anyway.  Lifetime resolution should
+                            // emit a "missing lifetime specifier" diagnostic.
+                            let res =
+                                LifetimeRes::Anonymous { binder: DUMMY_NODE_ID, elided: true };
+                            for id in node_ids {
+                                self.record_lifetime_res(id, res);
+                            }
+                            break;
+                        }
+                        LifetimeRibKind::AnonymousCreateParameter { .. }
+                        | LifetimeRibKind::Generics { .. }
+                        | LifetimeRibKind::ConstGeneric
+                        | LifetimeRibKind::AnonConst => {}
+                    }
+                }
+                continue;
+            }
+
+            let mut should_lint = true;
+            for rib in self.lifetime_ribs.iter().rev() {
+                match rib.kind {
+                    // In create-parameter mode we error here because we don't want to support
+                    // deprecated impl elision in new features like impl elision and `async fn`,
+                    // both of which work using the `CreateParameter` mode:
+                    //
+                    //     impl Foo for std::cell::Ref<u32> // note lack of '_
+                    //     async fn foo(_: std::cell::Ref<u32>) { ... }
+                    LifetimeRibKind::AnonymousCreateParameter { report_in_path: true, .. } => {
+                        let sess = self.r.session;
+                        let mut err = rustc_errors::struct_span_err!(
+                            sess,
+                            path_span,
+                            E0726,
+                            "implicit elided lifetime not allowed here"
+                        );
+                        rustc_errors::add_elided_lifetime_in_path_suggestion(
+                            sess.source_map(),
+                            &mut err,
+                            expected_lifetimes,
+                            path_span,
+                            !segment.has_generic_args,
+                            elided_lifetime_span,
+                        );
+                        err.note("assuming a `'static` lifetime...");
+                        err.emit();
+                        should_lint = false;
+
+                        for id in node_ids {
+                            self.record_lifetime_res(id, LifetimeRes::Error);
+                        }
+                        break;
+                    }
+                    // Do not create a parameter for patterns and expressions.
+                    LifetimeRibKind::AnonymousCreateParameter { binder, .. } => {
+                        for id in node_ids {
+                            let res = self.create_fresh_lifetime(id, ident, binder);
+                            self.record_lifetime_res(id, res);
+                        }
+                        break;
+                    }
+                    // `PassThrough` is the normal case.
+                    LifetimeRibKind::AnonymousPassThrough(binder, _) => {
+                        let res = LifetimeRes::Anonymous { binder, elided: true };
+                        for id in node_ids {
+                            self.record_lifetime_res(id, res);
+                        }
+                        break;
+                    }
+                    // `LifetimeRes::Error`, which would usually be used in the case of
+                    // `ReportError`, is unsuitable here, as we don't emit an error yet.  Instead,
+                    // we simply resolve to an implicit lifetime, which will be checked later, at
+                    // which point a suitable error will be emitted.
+                    LifetimeRibKind::AnonymousReportError | LifetimeRibKind::Item => {
+                        // FIXME(cjgillot) This resolution is wrong, but this does not matter
+                        // since these cases are erroneous anyway.  Lifetime resolution should
+                        // emit a "missing lifetime specifier" diagnostic.
+                        let res = LifetimeRes::Anonymous { binder: DUMMY_NODE_ID, elided: true };
+                        for id in node_ids {
+                            self.record_lifetime_res(id, res);
+                        }
+                        break;
+                    }
+                    LifetimeRibKind::Generics { .. }
+                    | LifetimeRibKind::ConstGeneric
+                    | LifetimeRibKind::AnonConst => {}
+                }
+            }
+
+            if should_lint {
                 self.r.lint_buffer.buffer_lint_with_diagnostic(
                     lint::builtin::ELIDED_LIFETIMES_IN_PATHS,
                     segment_id,
@@ -1453,13 +1716,9 @@
 
     /// Searches the current set of local scopes for labels. Returns the `NodeId` of the resolved
     /// label and reports an error if the label is not found or is unreachable.
-    fn resolve_label(&mut self, mut label: Ident) -> Option<NodeId> {
+    fn resolve_label(&mut self, mut label: Ident) -> Result<(NodeId, Span), ResolutionError<'a>> {
         let mut suggestion = None;
 
-        // Preserve the original span so that errors contain "in this macro invocation"
-        // information.
-        let original_span = label.span;
-
         for i in (0..self.label_ribs.len()).rev() {
             let rib = &self.label_ribs[i];
 
@@ -1475,18 +1734,13 @@
             if let Some((ident, id)) = rib.bindings.get_key_value(&ident) {
                 let definition_span = ident.span;
                 return if self.is_label_valid_from_rib(i) {
-                    Some(*id)
+                    Ok((*id, definition_span))
                 } else {
-                    self.report_error(
-                        original_span,
-                        ResolutionError::UnreachableLabel {
-                            name: label.name,
-                            definition_span,
-                            suggestion,
-                        },
-                    );
-
-                    None
+                    Err(ResolutionError::UnreachableLabel {
+                        name: label.name,
+                        definition_span,
+                        suggestion,
+                    })
                 };
             }
 
@@ -1495,11 +1749,7 @@
             suggestion = suggestion.or_else(|| self.suggestion_for_label_in_rib(i, label));
         }
 
-        self.report_error(
-            original_span,
-            ResolutionError::UndeclaredLabel { name: label.name, suggestion },
-        );
-        None
+        Err(ResolutionError::UndeclaredLabel { name: label.name, suggestion })
     }
 
     /// Determine whether or not a label from the `rib_index`th label rib is reachable.
@@ -1507,22 +1757,8 @@
         let ribs = &self.label_ribs[rib_index + 1..];
 
         for rib in ribs {
-            match rib.kind {
-                NormalRibKind | MacroDefinition(..) => {
-                    // Nothing to do. Continue.
-                }
-
-                AssocItemRibKind
-                | ClosureOrAsyncRibKind
-                | FnItemRibKind
-                | ItemRibKind(..)
-                | ConstantItemRibKind(..)
-                | ModuleRibKind(..)
-                | ForwardGenericParamBanRibKind
-                | ConstParamTyRibKind
-                | InlineAsmSymRibKind => {
-                    return false;
-                }
+            if rib.kind.is_label_barrier() {
+                return false;
             }
         }
 
@@ -1536,7 +1772,7 @@
                 &generics.params,
                 ItemRibKind(HasGenericParams::Yes),
                 LifetimeRibKind::Generics {
-                    parent: item.id,
+                    binder: item.id,
                     kind: LifetimeBinderKind::Item,
                     span: generics.span,
                 },
@@ -1606,7 +1842,7 @@
                     &generics.params,
                     ItemRibKind(HasGenericParams::Yes),
                     LifetimeRibKind::Generics {
-                        parent: item.id,
+                        binder: item.id,
                         kind: LifetimeBinderKind::Item,
                         span: generics.span,
                     },
@@ -1619,7 +1855,7 @@
                     &generics.params,
                     ItemRibKind(HasGenericParams::Yes),
                     LifetimeRibKind::Generics {
-                        parent: item.id,
+                        binder: item.id,
                         kind: LifetimeBinderKind::Function,
                         span: generics.span,
                     },
@@ -1651,7 +1887,7 @@
                     &generics.params,
                     ItemRibKind(HasGenericParams::Yes),
                     LifetimeRibKind::Generics {
-                        parent: item.id,
+                        binder: item.id,
                         kind: LifetimeBinderKind::Item,
                         span: generics.span,
                     },
@@ -1662,72 +1898,7 @@
                             |this| {
                                 this.visit_generics(generics);
                                 walk_list!(this, visit_param_bound, bounds, BoundKind::SuperTraits);
-
-                                let walk_assoc_item =
-                                    |this: &mut Self,
-                                     generics: &Generics,
-                                     kind,
-                                     item: &'ast AssocItem| {
-                                        this.with_generic_param_rib(
-                                            &generics.params,
-                                            AssocItemRibKind,
-                                            LifetimeRibKind::Generics {
-                                                parent: item.id,
-                                                span: generics.span,
-                                                kind,
-                                            },
-                                            |this| {
-                                                visit::walk_assoc_item(this, item, AssocCtxt::Trait)
-                                            },
-                                        );
-                                    };
-
-                                this.with_trait_items(items, |this| {
-                                    for item in items {
-                                        match &item.kind {
-                                            AssocItemKind::Const(_, ty, default) => {
-                                                this.visit_ty(ty);
-                                                // Only impose the restrictions of `ConstRibKind` for an
-                                                // actual constant expression in a provided default.
-                                                if let Some(expr) = default {
-                                                    // We allow arbitrary const expressions inside of associated consts,
-                                                    // even if they are potentially not const evaluatable.
-                                                    //
-                                                    // Type parameters can already be used and as associated consts are
-                                                    // not used as part of the type system, this is far less surprising.
-                                                    this.with_constant_rib(
-                                                        IsRepeatExpr::No,
-                                                        HasGenericParams::Yes,
-                                                        None,
-                                                        |this| this.visit_expr(expr),
-                                                    );
-                                                }
-                                            }
-                                            AssocItemKind::Fn(box Fn { generics, .. }) => {
-                                                walk_assoc_item(
-                                                    this,
-                                                    generics,
-                                                    LifetimeBinderKind::Function,
-                                                    item,
-                                                );
-                                            }
-                                            AssocItemKind::TyAlias(box TyAlias {
-                                                generics,
-                                                ..
-                                            }) => {
-                                                walk_assoc_item(
-                                                    this,
-                                                    generics,
-                                                    LifetimeBinderKind::Item,
-                                                    item,
-                                                );
-                                            }
-                                            AssocItemKind::MacCall(_) => {
-                                                panic!("unexpanded macro in resolve!")
-                                            }
-                                        };
-                                    }
-                                });
+                                this.resolve_trait_items(items);
                             },
                         );
                     },
@@ -1740,7 +1911,7 @@
                     &generics.params,
                     ItemRibKind(HasGenericParams::Yes),
                     LifetimeRibKind::Generics {
-                        parent: item.id,
+                        binder: item.id,
                         kind: LifetimeBinderKind::Item,
                         span: generics.span,
                     },
@@ -1802,7 +1973,7 @@
 
     fn with_generic_param_rib<'c, F>(
         &'c mut self,
-        params: &'c Vec<GenericParam>,
+        params: &'c [GenericParam],
         kind: RibKind<'a>,
         lifetime_kind: LifetimeRibKind,
         f: F,
@@ -1810,10 +1981,15 @@
         F: FnOnce(&mut Self),
     {
         debug!("with_generic_param_rib");
+        let LifetimeRibKind::Generics { binder, span: generics_span, kind: generics_kind, .. }
+            = lifetime_kind else { panic!() };
+
         let mut function_type_rib = Rib::new(kind);
         let mut function_value_rib = Rib::new(kind);
         let mut function_lifetime_rib = LifetimeRib::new(lifetime_kind);
         let mut seen_bindings = FxHashMap::default();
+        // Store all seen lifetimes names from outer scopes.
+        let mut seen_lifetimes = FxHashSet::default();
 
         // We also can't shadow bindings from the parent item
         if let AssocItemRibKind = kind {
@@ -1829,16 +2005,36 @@
             add_bindings_for_ns(TypeNS);
         }
 
+        // Forbid shadowing lifetime bindings
+        for rib in self.lifetime_ribs.iter().rev() {
+            seen_lifetimes.extend(rib.bindings.iter().map(|(ident, _)| *ident));
+            if let LifetimeRibKind::Item = rib.kind {
+                break;
+            }
+        }
+
         for param in params {
             let ident = param.ident.normalize_to_macros_2_0();
             debug!("with_generic_param_rib: {}", param.id);
 
+            if let GenericParamKind::Lifetime = param.kind
+                && let Some(&original) = seen_lifetimes.get(&ident)
+            {
+                diagnostics::signal_lifetime_shadowing(self.r.session, original, param.ident);
+                // Record lifetime res, so lowering knows there is something fishy.
+                self.record_lifetime_res(param.id, LifetimeRes::Error);
+                continue;
+            }
+
             match seen_bindings.entry(ident) {
                 Entry::Occupied(entry) => {
                     let span = *entry.get();
                     let err = ResolutionError::NameAlreadyUsedInParameterList(ident.name, span);
-                    if !matches!(param.kind, GenericParamKind::Lifetime) {
-                        self.report_error(param.ident.span, err);
+                    self.report_error(param.ident.span, err);
+                    if let GenericParamKind::Lifetime = param.kind {
+                        // Record lifetime res, so lowering knows there is something fishy.
+                        self.record_lifetime_res(param.id, LifetimeRes::Error);
+                        continue;
                     }
                 }
                 Entry::Vacant(entry) => {
@@ -1855,6 +2051,8 @@
                 )
                 .span_label(param.ident.span, "`'_` is a reserved lifetime name")
                 .emit();
+                // Record lifetime res, so lowering knows there is something fishy.
+                self.record_lifetime_res(param.id, LifetimeRes::Error);
                 continue;
             }
 
@@ -1868,6 +2066,8 @@
                 )
                 .span_label(param.ident.span, "'static is a reserved lifetime name")
                 .emit();
+                // Record lifetime res, so lowering knows there is something fishy.
+                self.record_lifetime_res(param.id, LifetimeRes::Error);
                 continue;
             }
 
@@ -1878,14 +2078,18 @@
                 GenericParamKind::Type { .. } => (&mut function_type_rib, DefKind::TyParam),
                 GenericParamKind::Const { .. } => (&mut function_value_rib, DefKind::ConstParam),
                 GenericParamKind::Lifetime => {
-                    let LifetimeRibKind::Generics { parent, .. } = lifetime_kind else { panic!() };
-                    let res = LifetimeRes::Param { param: def_id, binder: parent };
+                    let res = LifetimeRes::Param { param: def_id, binder };
                     self.record_lifetime_res(param.id, res);
                     function_lifetime_rib.bindings.insert(ident, (param.id, res));
                     continue;
                 }
             };
-            let res = Res::Def(def_kind, def_id.to_def_id());
+
+            let res = match kind {
+                ItemRibKind(..) | AssocItemRibKind => Res::Def(def_kind, def_id.to_def_id()),
+                NormalRibKind => Res::Err,
+                _ => bug!("Unexpected rib kind {:?}", kind),
+            };
             self.r.record_partial_res(param.id, PartialRes::new(res));
             rib.bindings.insert(ident, res);
         }
@@ -1899,6 +2103,14 @@
         self.ribs[TypeNS].pop();
         self.ribs[ValueNS].pop();
         self.lifetime_ribs.pop();
+
+        if let LifetimeBinderKind::BareFnType
+        | LifetimeBinderKind::WhereBound
+        | LifetimeBinderKind::Function
+        | LifetimeBinderKind::ImplBlock = generics_kind
+        {
+            self.maybe_report_lifetime_uses(generics_span, params)
+        }
     }
 
     fn with_label_rib(&mut self, kind: RibKind<'a>, f: impl FnOnce(&mut Self)) {
@@ -1962,34 +2174,75 @@
     }
 
     /// When evaluating a `trait` use its associated types' idents for suggestions in E0412.
-    fn with_trait_items<T>(
-        &mut self,
-        trait_items: &'ast [P<AssocItem>],
-        f: impl FnOnce(&mut Self) -> T,
-    ) -> T {
+    fn resolve_trait_items(&mut self, trait_items: &'ast [P<AssocItem>]) {
         let trait_assoc_items =
             replace(&mut self.diagnostic_metadata.current_trait_assoc_items, Some(&trait_items));
-        let result = f(self);
+
+        let walk_assoc_item =
+            |this: &mut Self, generics: &Generics, kind, item: &'ast AssocItem| {
+                this.with_generic_param_rib(
+                    &generics.params,
+                    AssocItemRibKind,
+                    LifetimeRibKind::Generics { binder: item.id, span: generics.span, kind },
+                    |this| visit::walk_assoc_item(this, item, AssocCtxt::Trait),
+                );
+            };
+
+        for item in trait_items {
+            match &item.kind {
+                AssocItemKind::Const(_, ty, default) => {
+                    self.visit_ty(ty);
+                    // Only impose the restrictions of `ConstRibKind` for an
+                    // actual constant expression in a provided default.
+                    if let Some(expr) = default {
+                        // We allow arbitrary const expressions inside of associated consts,
+                        // even if they are potentially not const evaluatable.
+                        //
+                        // Type parameters can already be used and as associated consts are
+                        // not used as part of the type system, this is far less surprising.
+                        self.with_constant_rib(
+                            IsRepeatExpr::No,
+                            HasGenericParams::Yes,
+                            None,
+                            |this| this.visit_expr(expr),
+                        );
+                    }
+                }
+                AssocItemKind::Fn(box Fn { generics, .. }) => {
+                    walk_assoc_item(self, generics, LifetimeBinderKind::Function, item);
+                }
+                AssocItemKind::TyAlias(box TyAlias { generics, .. }) => {
+                    walk_assoc_item(self, generics, LifetimeBinderKind::Item, item);
+                }
+                AssocItemKind::MacCall(_) => {
+                    panic!("unexpanded macro in resolve!")
+                }
+            };
+        }
+
         self.diagnostic_metadata.current_trait_assoc_items = trait_assoc_items;
-        result
     }
 
     /// This is called to resolve a trait reference from an `impl` (i.e., `impl Trait for Foo`).
     fn with_optional_trait_ref<T>(
         &mut self,
         opt_trait_ref: Option<&TraitRef>,
+        self_type: &'ast Ty,
         f: impl FnOnce(&mut Self, Option<DefId>) -> T,
     ) -> T {
         let mut new_val = None;
         let mut new_id = None;
         if let Some(trait_ref) = opt_trait_ref {
             let path: Vec<_> = Segment::from_path(&trait_ref.path);
+            self.diagnostic_metadata.currently_processing_impl_trait =
+                Some((trait_ref.clone(), self_type.clone()));
             let res = self.smart_resolve_path_fragment(
                 None,
                 &path,
                 PathSource::Trait(AliasPossibility::No),
                 Finalize::new(trait_ref.ref_id, trait_ref.path.span),
             );
+            self.diagnostic_metadata.currently_processing_impl_trait = None;
             if let Some(def_id) = res.base_res().opt_def_id() {
                 new_id = Some(def_id);
                 new_val = Some((self.r.expect_module(def_id), trait_ref.clone()));
@@ -2025,142 +2278,159 @@
     ) {
         debug!("resolve_implementation");
         // If applicable, create a rib for the type parameters.
-        self.with_generic_param_rib(&generics.params, ItemRibKind(HasGenericParams::Yes), LifetimeRibKind::Generics { span: generics.span, parent: item_id, kind: LifetimeBinderKind::ImplBlock }, |this| {
-            // Dummy self type for better errors if `Self` is used in the trait path.
-            this.with_self_rib(Res::SelfTy { trait_: None, alias_to: None }, |this| {
-                this.with_lifetime_rib(LifetimeRibKind::AnonymousCreateParameter(item_id), |this| {
-                    // Resolve the trait reference, if necessary.
-                    this.with_optional_trait_ref(opt_trait_reference.as_ref(), |this, trait_id| {
-                        let item_def_id = this.r.local_def_id(item_id);
+        self.with_generic_param_rib(
+            &generics.params,
+            ItemRibKind(HasGenericParams::Yes),
+            LifetimeRibKind::Generics {
+                span: generics.span,
+                binder: item_id,
+                kind: LifetimeBinderKind::ImplBlock
+            },
+            |this| {
+                // Dummy self type for better errors if `Self` is used in the trait path.
+                this.with_self_rib(Res::SelfTy { trait_: None, alias_to: None }, |this| {
+                    this.with_lifetime_rib(
+                        LifetimeRibKind::AnonymousCreateParameter {
+                            binder: item_id,
+                            report_in_path: true
+                        },
+                        |this| {
+                            // Resolve the trait reference, if necessary.
+                            this.with_optional_trait_ref(
+                                opt_trait_reference.as_ref(),
+                                self_type,
+                                |this, trait_id| {
+                                    let item_def_id = this.r.local_def_id(item_id);
 
-                        // Register the trait definitions from here.
-                        if let Some(trait_id) = trait_id {
-                            this.r.trait_impls.entry(trait_id).or_default().push(item_def_id);
-                        }
+                                    // Register the trait definitions from here.
+                                    if let Some(trait_id) = trait_id {
+                                        this.r.trait_impls.entry(trait_id).or_default().push(item_def_id);
+                                    }
 
-                        let item_def_id = item_def_id.to_def_id();
-                        let res =
-                            Res::SelfTy { trait_: trait_id, alias_to: Some((item_def_id, false)) };
-                        this.with_self_rib(res, |this| {
-                            if let Some(trait_ref) = opt_trait_reference.as_ref() {
-                                // Resolve type arguments in the trait path.
-                                visit::walk_trait_ref(this, trait_ref);
-                            }
-                            // Resolve the self type.
-                            this.visit_ty(self_type);
-                            // Resolve the generic parameters.
-                            this.visit_generics(generics);
+                                    let item_def_id = item_def_id.to_def_id();
+                                    let res = Res::SelfTy {
+                                        trait_: trait_id,
+                                        alias_to: Some((item_def_id, false)),
+                                    };
+                                    this.with_self_rib(res, |this| {
+                                        if let Some(trait_ref) = opt_trait_reference.as_ref() {
+                                            // Resolve type arguments in the trait path.
+                                            visit::walk_trait_ref(this, trait_ref);
+                                        }
+                                        // Resolve the self type.
+                                        this.visit_ty(self_type);
+                                        // Resolve the generic parameters.
+                                        this.visit_generics(generics);
 
-                            // Resolve the items within the impl.
-                            this.with_lifetime_rib(LifetimeRibKind::AnonymousPassThrough(item_id),
-                                |this| {
-                                    this.with_current_self_type(self_type, |this| {
-                                        this.with_self_rib_ns(ValueNS, Res::SelfCtor(item_def_id), |this| {
-                                            debug!("resolve_implementation with_self_rib_ns(ValueNS, ...)");
-                                            for item in impl_items {
-                                                use crate::ResolutionError::*;
-                                                match &item.kind {
-                                                    AssocItemKind::Const(_default, _ty, _expr) => {
-                                                        debug!("resolve_implementation AssocItemKind::Const");
-                                                        // If this is a trait impl, ensure the const
-                                                        // exists in trait
-                                                        this.check_trait_item(
-                                                            item.id,
-                                                            item.ident,
-                                                            &item.kind,
-                                                            ValueNS,
-                                                            item.span,
-                                                            |i, s, c| ConstNotMemberOfTrait(i, s, c),
-                                                        );
-
-                                                        // We allow arbitrary const expressions inside of associated consts,
-                                                        // even if they are potentially not const evaluatable.
-                                                        //
-                                                        // Type parameters can already be used and as associated consts are
-                                                        // not used as part of the type system, this is far less surprising.
-                                                        this.with_constant_rib(
-                                                            IsRepeatExpr::No,
-                                                            HasGenericParams::Yes,
-                                                            None,
-                                                            |this| {
-                                                                visit::walk_assoc_item(
-                                                                    this,
-                                                                    item,
-                                                                    AssocCtxt::Impl,
-                                                                )
-                                                            },
-                                                        );
-                                                    }
-                                                    AssocItemKind::Fn(box Fn { generics, .. }) => {
-                                                        debug!("resolve_implementation AssocItemKind::Fn");
-                                                        // We also need a new scope for the impl item type parameters.
-                                                        this.with_generic_param_rib(
-                                                            &generics.params,
-                                                            AssocItemRibKind,
-                                                            LifetimeRibKind::Generics { parent: item.id, span: generics.span, kind: LifetimeBinderKind::Function },
-                                                            |this| {
-                                                                // If this is a trait impl, ensure the method
-                                                                // exists in trait
-                                                                this.check_trait_item(
-                                                                    item.id,
-                                                                    item.ident,
-                                                                    &item.kind,
-                                                                    ValueNS,
-                                                                    item.span,
-                                                                    |i, s, c| MethodNotMemberOfTrait(i, s, c),
-                                                                );
-
-                                                                visit::walk_assoc_item(
-                                                                    this,
-                                                                    item,
-                                                                    AssocCtxt::Impl,
-                                                                )
-                                                            },
-                                                        );
-                                                    }
-                                                    AssocItemKind::TyAlias(box TyAlias {
-                                                        generics, ..
-                                                    }) => {
-                                                        debug!("resolve_implementation AssocItemKind::TyAlias");
-                                                        // We also need a new scope for the impl item type parameters.
-                                                        this.with_generic_param_rib(
-                                                            &generics.params,
-                                                            AssocItemRibKind,
-                                                            LifetimeRibKind::Generics { parent: item.id, span: generics.span, kind: LifetimeBinderKind::Item },
-                                                            |this| {
-                                                                // If this is a trait impl, ensure the type
-                                                                // exists in trait
-                                                                this.check_trait_item(
-                                                                    item.id,
-                                                                    item.ident,
-                                                                    &item.kind,
-                                                                    TypeNS,
-                                                                    item.span,
-                                                                    |i, s, c| TypeNotMemberOfTrait(i, s, c),
-                                                                );
-
-                                                                visit::walk_assoc_item(
-                                                                    this,
-                                                                    item,
-                                                                    AssocCtxt::Impl,
-                                                                )
-                                                            },
-                                                        );
-                                                    }
-                                                    AssocItemKind::MacCall(_) => {
-                                                        panic!("unexpanded macro in resolve!")
-                                                    }
-                                                }
-                                            }
-                                        });
+                                        // Resolve the items within the impl.
+                                        this.with_lifetime_rib(LifetimeRibKind::AnonymousPassThrough(item_id,false),
+                                            |this| {
+                                                this.with_current_self_type(self_type, |this| {
+                                                    this.with_self_rib_ns(ValueNS, Res::SelfCtor(item_def_id), |this| {
+                                                        debug!("resolve_implementation with_self_rib_ns(ValueNS, ...)");
+                                                        for item in impl_items {
+                                                            this.resolve_impl_item(&**item);
+                                                        }
+                                                    });
+                                                });
+                                            },
+                                        );
                                     });
                                 },
                             );
-                        });
-                    });
+                        },
+                    );
                 });
-            });
-        });
+            },
+        );
+    }
+
+    fn resolve_impl_item(&mut self, item: &'ast AssocItem) {
+        use crate::ResolutionError::*;
+        match &item.kind {
+            AssocItemKind::Const(_, ty, default) => {
+                debug!("resolve_implementation AssocItemKind::Const");
+                // If this is a trait impl, ensure the const
+                // exists in trait
+                self.check_trait_item(
+                    item.id,
+                    item.ident,
+                    &item.kind,
+                    ValueNS,
+                    item.span,
+                    |i, s, c| ConstNotMemberOfTrait(i, s, c),
+                );
+
+                self.visit_ty(ty);
+                if let Some(expr) = default {
+                    // We allow arbitrary const expressions inside of associated consts,
+                    // even if they are potentially not const evaluatable.
+                    //
+                    // Type parameters can already be used and as associated consts are
+                    // not used as part of the type system, this is far less surprising.
+                    self.with_constant_rib(IsRepeatExpr::No, HasGenericParams::Yes, None, |this| {
+                        this.visit_expr(expr)
+                    });
+                }
+            }
+            AssocItemKind::Fn(box Fn { generics, .. }) => {
+                debug!("resolve_implementation AssocItemKind::Fn");
+                // We also need a new scope for the impl item type parameters.
+                self.with_generic_param_rib(
+                    &generics.params,
+                    AssocItemRibKind,
+                    LifetimeRibKind::Generics {
+                        binder: item.id,
+                        span: generics.span,
+                        kind: LifetimeBinderKind::Function,
+                    },
+                    |this| {
+                        // If this is a trait impl, ensure the method
+                        // exists in trait
+                        this.check_trait_item(
+                            item.id,
+                            item.ident,
+                            &item.kind,
+                            ValueNS,
+                            item.span,
+                            |i, s, c| MethodNotMemberOfTrait(i, s, c),
+                        );
+
+                        visit::walk_assoc_item(this, item, AssocCtxt::Impl)
+                    },
+                );
+            }
+            AssocItemKind::TyAlias(box TyAlias { generics, .. }) => {
+                debug!("resolve_implementation AssocItemKind::TyAlias");
+                // We also need a new scope for the impl item type parameters.
+                self.with_generic_param_rib(
+                    &generics.params,
+                    AssocItemRibKind,
+                    LifetimeRibKind::Generics {
+                        binder: item.id,
+                        span: generics.span,
+                        kind: LifetimeBinderKind::Item,
+                    },
+                    |this| {
+                        // If this is a trait impl, ensure the type
+                        // exists in trait
+                        this.check_trait_item(
+                            item.id,
+                            item.ident,
+                            &item.kind,
+                            TypeNS,
+                            item.span,
+                            |i, s, c| TypeNotMemberOfTrait(i, s, c),
+                        );
+
+                        visit::walk_assoc_item(this, item, AssocCtxt::Impl)
+                    },
+                );
+            }
+            AssocItemKind::MacCall(_) => {
+                panic!("unexpanded macro in resolve!")
+            }
+        }
     }
 
     fn check_trait_item<F>(
@@ -3026,6 +3296,11 @@
             if label.ident.as_str().as_bytes()[1] != b'_' {
                 self.diagnostic_metadata.unused_labels.insert(id, label.ident.span);
             }
+
+            if let Ok((_, orig_span)) = self.resolve_label(label.ident) {
+                diagnostics::signal_label_shadowing(self.r.session, orig_span, label.ident)
+            }
+
             self.with_label_rib(NormalRibKind, |this| {
                 let ident = label.ident.normalize_to_macro_rules();
                 this.label_ribs.last_mut().unwrap().bindings.insert(ident, id);
@@ -3131,10 +3406,15 @@
             }
 
             ExprKind::Break(Some(label), _) | ExprKind::Continue(Some(label)) => {
-                if let Some(node_id) = self.resolve_label(label.ident) {
-                    // Since this res is a label, it is never read.
-                    self.r.label_res_map.insert(expr.id, node_id);
-                    self.diagnostic_metadata.unused_labels.remove(&node_id);
+                match self.resolve_label(label.ident) {
+                    Ok((node_id, _)) => {
+                        // Since this res is a label, it is never read.
+                        self.r.label_res_map.insert(expr.id, node_id);
+                        self.diagnostic_metadata.unused_labels.remove(&node_id);
+                    }
+                    Err(error) => {
+                        self.report_error(label.ident.span, error);
+                    }
                 }
 
                 // visit `break` argument if any
@@ -3258,7 +3538,9 @@
                     })
                 });
             }
-            ExprKind::Async(..) | ExprKind::Closure(..) => {
+            // For closures, ClosureOrAsyncRibKind is added in visit_fn
+            ExprKind::Closure(..) => visit::walk_expr(self, expr),
+            ExprKind::Async(..) => {
                 self.with_label_rib(ClosureOrAsyncRibKind, |this| visit::walk_expr(this, expr));
             }
             ExprKind::Repeat(ref elem, ref ct) => {
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index 4f07d00..68bcba7 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -1,18 +1,18 @@
 use crate::diagnostics::{ImportSuggestion, LabelSuggestion, TypoSuggestion};
 use crate::late::lifetimes::{ElisionFailureInfo, LifetimeContext};
 use crate::late::{AliasPossibility, LateResolutionVisitor, RibKind};
-use crate::late::{LifetimeBinderKind, LifetimeRibKind};
+use crate::late::{LifetimeBinderKind, LifetimeRibKind, LifetimeUseSet};
 use crate::path_names_to_string;
 use crate::{Module, ModuleKind, ModuleOrUniformRoot};
 use crate::{PathResult, PathSource, Segment};
 
-use rustc_ast::visit::{FnCtxt, FnKind};
+use rustc_ast::visit::{FnCtxt, FnKind, LifetimeCtxt};
 use rustc_ast::{
     self as ast, AssocItemKind, Expr, ExprKind, GenericParam, GenericParamKind, Item, ItemKind,
     NodeId, Path, Ty, TyKind,
 };
 use rustc_ast_pretty::pprust::path_segment_to_string;
-use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
 use rustc_errors::{
     pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
     MultiSpan,
@@ -20,9 +20,11 @@
 use rustc_hir as hir;
 use rustc_hir::def::Namespace::{self, *};
 use rustc_hir::def::{self, CtorKind, CtorOf, DefKind};
-use rustc_hir::def_id::{DefId, CRATE_DEF_ID, LOCAL_CRATE};
+use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE};
 use rustc_hir::PrimTy;
+use rustc_session::lint;
 use rustc_session::parse::feature_err;
+use rustc_session::Session;
 use rustc_span::edition::Edition;
 use rustc_span::hygiene::MacroKind;
 use rustc_span::lev_distance::find_best_match_for_name;
@@ -57,13 +59,13 @@
     }
 }
 
-crate enum MissingLifetimeSpot<'tcx> {
+pub(crate) enum MissingLifetimeSpot<'tcx> {
     Generics(&'tcx hir::Generics<'tcx>),
     HigherRanked { span: Span, span_type: ForLifetimeSpanType },
     Static,
 }
 
-crate enum ForLifetimeSpanType {
+pub(crate) enum ForLifetimeSpanType {
     BoundEmpty,
     BoundTail,
     TypeEmpty,
@@ -71,14 +73,14 @@
 }
 
 impl ForLifetimeSpanType {
-    crate fn descr(&self) -> &'static str {
+    pub(crate) fn descr(&self) -> &'static str {
         match self {
             Self::BoundEmpty | Self::BoundTail => "bound",
             Self::TypeEmpty | Self::TypeTail => "type",
         }
     }
 
-    crate fn suggestion(&self, sugg: &str) -> String {
+    pub(crate) fn suggestion(&self, sugg: &str) -> String {
         match self {
             Self::BoundEmpty | Self::TypeEmpty => format!("for<{}> ", sugg),
             Self::BoundTail | Self::TypeTail => format!(", {}", sugg),
@@ -143,6 +145,8 @@
         let is_expected = &|res| source.is_expected(res);
         let is_enum_variant = &|res| matches!(res, Res::Def(DefKind::Variant, _));
 
+        debug!(?res, ?source);
+
         // Make the base error.
         struct BaseError<'a> {
             msg: String,
@@ -247,6 +251,8 @@
         let mut err =
             self.r.session.struct_span_err_with_code(base_error.span, &base_error.msg, code);
 
+        self.suggest_swapping_misplaced_self_ty_and_trait(&mut err, source, res, base_error.span);
+
         if let Some(sugg) = base_error.suggestion {
             err.span_suggestion_verbose(sugg.0, sugg.1, sugg.2, Applicability::MaybeIncorrect);
         }
@@ -262,13 +268,21 @@
             );
         }
         match (source, self.diagnostic_metadata.in_if_condition) {
-            (PathSource::Expr(_), Some(Expr { span, kind: ExprKind::Assign(..), .. })) => {
-                err.span_suggestion_verbose(
-                    span.shrink_to_lo(),
-                    "you might have meant to use pattern matching",
-                    "let ".to_string(),
-                    Applicability::MaybeIncorrect,
-                );
+            (
+                PathSource::Expr(_),
+                Some(Expr { span: expr_span, kind: ExprKind::Assign(lhs, _, _), .. }),
+            ) => {
+                // Icky heuristic so we don't suggest:
+                // `if (i + 2) = 2` => `if let (i + 2) = 2` (approximately pattern)
+                // `if 2 = i` => `if let 2 = i` (lhs needs to contain error span)
+                if lhs.is_approximately_pattern() && lhs.span.contains(span) {
+                    err.span_suggestion_verbose(
+                        expr_span.shrink_to_lo(),
+                        "you might have meant to use pattern matching",
+                        "let ",
+                        Applicability::MaybeIncorrect,
+                    );
+                }
             }
             _ => {}
         }
@@ -279,7 +293,7 @@
             err.span_suggestion_short(
                 span,
                 "you might have meant to use `self` here instead",
-                "self".to_string(),
+                "self",
                 Applicability::MaybeIncorrect,
             );
             if !self.self_value_is_available(path[0].ident.span) {
@@ -302,7 +316,7 @@
                         span,
                         "if you meant to use `self`, you are also missing a `self` receiver \
                          argument",
-                        sugg.to_string(),
+                        sugg,
                         Applicability::MaybeIncorrect,
                     );
                 }
@@ -318,6 +332,16 @@
                 span,
                 "`Self` is only available in impls, traits, and type definitions".to_string(),
             );
+            if let Some(item_kind) = self.diagnostic_metadata.current_item {
+                err.span_label(
+                    item_kind.ident.span,
+                    format!(
+                        "`Self` not allowed in {} {}",
+                        item_kind.kind.article(),
+                        item_kind.kind.descr()
+                    ),
+                );
+            }
             return (err, Vec::new());
         }
         if is_self_value(path, ns) {
@@ -361,7 +385,7 @@
                         err.span_suggestion_verbose(
                             span,
                             "add a `self` receiver parameter to make the associated `fn` a method",
-                            sugg.to_string(),
+                            sugg,
                             Applicability::MaybeIncorrect,
                         );
                         "doesn't"
@@ -375,13 +399,22 @@
                         );
                     }
                 }
+            } else if let Some(item_kind) = self.diagnostic_metadata.current_item {
+                err.span_label(
+                    item_kind.ident.span,
+                    format!(
+                        "`self` not allowed in {} {}",
+                        item_kind.kind.article(),
+                        item_kind.kind.descr()
+                    ),
+                );
             }
             return (err, Vec::new());
         }
 
         // Try to lookup name in more relaxed fashion for better error reporting.
         let ident = path.last().unwrap().ident;
-        let candidates = self
+        let mut candidates = self
             .r
             .lookup_import_candidates(ident, ns, &self.parent_scope, is_expected)
             .into_iter()
@@ -393,6 +426,18 @@
             })
             .collect::<Vec<_>>();
         let crate_def_id = CRATE_DEF_ID.to_def_id();
+        // Try to filter out intrinsics candidates, as long as we have
+        // some other candidates to suggest.
+        let intrinsic_candidates: Vec<_> = candidates
+            .drain_filter(|sugg| {
+                let path = path_names_to_string(&sugg.path);
+                path.starts_with("core::intrinsics::") || path.starts_with("std::intrinsics::")
+            })
+            .collect();
+        if candidates.is_empty() {
+            // Put them back if we have no more candidates to suggest...
+            candidates.extend(intrinsic_candidates);
+        }
         if candidates.is_empty() && is_expected(Res::Def(DefKind::Enum, crate_def_id)) {
             let mut enum_candidates: Vec<_> = self
                 .r
@@ -443,6 +488,8 @@
                 );
             }
         }
+        // Try Levenshtein algorithm.
+        let typo_sugg = self.lookup_typo_candidate(path, ns, is_expected);
         if path.len() == 1 && self.self_type_is_available() {
             if let Some(candidate) = self.lookup_assoc_candidate(ident, ns, is_expected) {
                 let self_is_available = self.self_value_is_available(path[0].ident.span);
@@ -452,7 +499,7 @@
                             err.span_suggestion(
                                 span,
                                 "you might have meant to use the available field",
-                                format!("self.{}", path_str),
+                                format!("self.{path_str}"),
                                 Applicability::MachineApplicable,
                             );
                         } else {
@@ -463,7 +510,7 @@
                         err.span_suggestion(
                             span,
                             "you might have meant to call the method",
-                            format!("self.{}", path_str),
+                            format!("self.{path_str}"),
                             Applicability::MachineApplicable,
                         );
                     }
@@ -474,11 +521,12 @@
                         err.span_suggestion(
                             span,
                             &format!("you might have meant to {}", candidate.action()),
-                            format!("Self::{}", path_str),
+                            format!("Self::{path_str}"),
                             Applicability::MachineApplicable,
                         );
                     }
                 }
+                self.r.add_typo_suggestion(&mut err, typo_sugg, ident_span);
                 return (err, candidates);
             }
 
@@ -493,16 +541,14 @@
 
                 err.span_suggestion(
                     call_span,
-                    &format!("try calling `{}` as a method", ident),
-                    format!("self.{}({})", path_str, args_snippet),
+                    &format!("try calling `{ident}` as a method"),
+                    format!("self.{path_str}({args_snippet})"),
                     Applicability::MachineApplicable,
                 );
                 return (err, candidates);
             }
         }
 
-        // Try Levenshtein algorithm.
-        let typo_sugg = self.lookup_typo_candidate(path, ns, is_expected);
         // Try context-dependent help if relaxed lookup didn't work.
         if let Some(res) = res {
             if self.smart_resolve_context_dependent_help(
@@ -596,7 +642,7 @@
                         err.span_suggestion_short(
                             pat_sp.between(ty_sp),
                             "use `=` if you meant to assign",
-                            " = ".to_string(),
+                            " = ",
                             Applicability::MaybeIncorrect,
                         );
                     }
@@ -626,7 +672,7 @@
                                 err.span_suggestion(
                                     span,
                                     "use the similarly named label",
-                                    label_ident.name.to_string(),
+                                    label_ident.name,
                                     Applicability::MaybeIncorrect,
                                 );
                                 // Do not lint against unused label when we suggest them.
@@ -640,7 +686,7 @@
                     err.span_suggestion(
                         span,
                         "perhaps you intended to use this type",
-                        correct.to_string(),
+                        correct,
                         Applicability::MaybeIncorrect,
                     );
                 }
@@ -671,7 +717,7 @@
                         err.span_suggestion_verbose(
                             constraint.ident.span.between(trait_ref.span),
                             "you might have meant to write a path instead of an associated type bound",
-                            "::".to_string(),
+                            "::",
                             Applicability::MachineApplicable,
                         );
                     }
@@ -680,6 +726,35 @@
         }
     }
 
+    fn suggest_swapping_misplaced_self_ty_and_trait(
+        &mut self,
+        err: &mut Diagnostic,
+        source: PathSource<'_>,
+        res: Option<Res>,
+        span: Span,
+    ) {
+        if let Some((trait_ref, self_ty)) =
+            self.diagnostic_metadata.currently_processing_impl_trait.clone()
+            && let TyKind::Path(_, self_ty_path) = &self_ty.kind
+            && let PathResult::Module(ModuleOrUniformRoot::Module(module)) =
+                self.resolve_path(&Segment::from_path(self_ty_path), Some(TypeNS), None)
+            && let ModuleKind::Def(DefKind::Trait, ..) = module.kind
+            && trait_ref.path.span == span
+            && let PathSource::Trait(_) = source
+            && let Some(Res::Def(DefKind::Struct | DefKind::Enum | DefKind::Union, _)) = res
+            && let Ok(self_ty_str) =
+                self.r.session.source_map().span_to_snippet(self_ty.span)
+            && let Ok(trait_ref_str) =
+                self.r.session.source_map().span_to_snippet(trait_ref.path.span)
+        {
+                err.multipart_suggestion(
+                    "`impl` items mention the trait being implemented first and the type it is being implemented for second",
+                    vec![(trait_ref.path.span, self_ty_str), (self_ty.span, trait_ref_str)],
+                    Applicability::MaybeIncorrect,
+                );
+        }
+    }
+
     fn get_single_associated_item(
         &mut self,
         path: &[Segment],
@@ -1034,7 +1109,7 @@
                 err.span_suggestion_verbose(
                     span.shrink_to_hi(),
                     "use `!` to invoke the macro",
-                    "!".to_string(),
+                    "!",
                     Applicability::MaybeIncorrect,
                 );
                 if path_str == "try" && span.rust_2015() {
@@ -1183,7 +1258,7 @@
                         err.span_suggestion(
                             span,
                             "use this syntax instead",
-                            path_str.to_string(),
+                            path_str,
                             Applicability::MaybeIncorrect,
                         );
                     }
@@ -1219,7 +1294,7 @@
 
     /// Given the target `ident` and `kind`, search for the similarly named associated item
     /// in `self.current_trait_ref`.
-    crate fn find_similarly_named_assoc_item(
+    pub(crate) fn find_similarly_named_assoc_item(
         &mut self,
         ident: Symbol,
         kind: &AssocItemKind,
@@ -1462,7 +1537,7 @@
                         err.span_suggestion_short(
                             colon_sp,
                             "maybe you meant to write `;` here",
-                            ";".to_string(),
+                            ";",
                             Applicability::MaybeIncorrect,
                         );
                     } else {
@@ -1473,7 +1548,7 @@
                             err.span_suggestion(
                                 colon_sp,
                                 "maybe you meant to write a path separator here",
-                                "::".to_string(),
+                                "::",
                                 Applicability::MaybeIncorrect,
                             );
                             show_label = false;
@@ -1727,12 +1802,12 @@
         }
     }
 
-    crate fn report_missing_type_error(
+    pub(crate) fn report_missing_type_error(
         &self,
         path: &[Segment],
     ) -> Option<(Span, &'static str, String, Applicability)> {
         let (ident, span) = match path {
-            [segment] if !segment.has_generic_args => {
+            [segment] if !segment.has_generic_args && segment.ident.name != kw::SelfUpper => {
                 (segment.ident.to_string(), segment.ident.span)
             }
             _ => return None,
@@ -1807,7 +1882,7 @@
 
     /// Given the target `label`, search the `rib_index`th label rib for similarly named labels,
     /// optionally returning the closest match and whether it is reachable.
-    crate fn suggestion_for_label_in_rib(
+    pub(crate) fn suggestion_for_label_in_rib(
         &self,
         rib_index: usize,
         label: Ident,
@@ -1819,7 +1894,7 @@
         let names = rib
             .bindings
             .iter()
-            .filter(|(id, _)| id.span.ctxt() == label.span.ctxt())
+            .filter(|(id, _)| id.span.eq_ctxt(label.span))
             .map(|(id, _)| id.name)
             .collect::<Vec<Symbol>>();
 
@@ -1832,7 +1907,77 @@
         })
     }
 
-    crate fn emit_undeclared_lifetime_error(
+    pub(crate) fn maybe_report_lifetime_uses(
+        &mut self,
+        generics_span: Span,
+        params: &[ast::GenericParam],
+    ) {
+        for (param_index, param) in params.iter().enumerate() {
+            let GenericParamKind::Lifetime = param.kind else { continue };
+
+            let def_id = self.r.local_def_id(param.id);
+
+            let use_set = self.lifetime_uses.remove(&def_id);
+            debug!(
+                "Use set for {:?}({:?} at {:?}) is {:?}",
+                def_id, param.ident, param.ident.span, use_set
+            );
+
+            let deletion_span = || {
+                if params.len() == 1 {
+                    // if sole lifetime, remove the entire `<>` brackets
+                    generics_span
+                } else if param_index == 0 {
+                    // if removing within `<>` brackets, we also want to
+                    // delete a leading or trailing comma as appropriate
+                    param.span().to(params[param_index + 1].span().shrink_to_lo())
+                } else {
+                    // if removing within `<>` brackets, we also want to
+                    // delete a leading or trailing comma as appropriate
+                    params[param_index - 1].span().shrink_to_hi().to(param.span())
+                }
+            };
+            match use_set {
+                Some(LifetimeUseSet::Many) => {}
+                Some(LifetimeUseSet::One { use_span, use_ctxt }) => {
+                    debug!(?param.ident, ?param.ident.span, ?use_span);
+
+                    let elidable = matches!(use_ctxt, LifetimeCtxt::Rptr);
+
+                    let deletion_span = deletion_span();
+                    self.r.lint_buffer.buffer_lint_with_diagnostic(
+                        lint::builtin::SINGLE_USE_LIFETIMES,
+                        param.id,
+                        param.ident.span,
+                        &format!("lifetime parameter `{}` only used once", param.ident),
+                        lint::BuiltinLintDiagnostics::SingleUseLifetime {
+                            param_span: param.ident.span,
+                            use_span: Some((use_span, elidable)),
+                            deletion_span,
+                        },
+                    );
+                }
+                None => {
+                    debug!(?param.ident, ?param.ident.span);
+
+                    let deletion_span = deletion_span();
+                    self.r.lint_buffer.buffer_lint_with_diagnostic(
+                        lint::builtin::UNUSED_LIFETIMES,
+                        param.id,
+                        param.ident.span,
+                        &format!("lifetime parameter `{}` never used", param.ident),
+                        lint::BuiltinLintDiagnostics::SingleUseLifetime {
+                            param_span: param.ident.span,
+                            use_span: None,
+                            deletion_span,
+                        },
+                    );
+                }
+            }
+        }
+    }
+
+    pub(crate) fn emit_undeclared_lifetime_error(
         &self,
         lifetime_ref: &ast::Lifetime,
         outer_lifetime_ref: Option<Ident>,
@@ -1863,7 +2008,7 @@
 
         for rib in self.lifetime_ribs.iter().rev() {
             match rib.kind {
-                LifetimeRibKind::Generics { parent: _, span, kind } => {
+                LifetimeRibKind::Generics { binder: _, span, kind } => {
                     if !span.can_be_used_for_suggestions() && suggest_note {
                         suggest_note = false; // Avoid displaying the same help multiple times.
                         err.span_label(
@@ -1928,7 +2073,7 @@
         err.emit();
     }
 
-    crate fn emit_non_static_lt_in_const_generic_error(&self, lifetime_ref: &ast::Lifetime) {
+    pub(crate) fn emit_non_static_lt_in_const_generic_error(&self, lifetime_ref: &ast::Lifetime) {
         struct_span_err!(
             self.r.session,
             lifetime_ref.ident.span,
@@ -1946,7 +2091,10 @@
     /// Non-static lifetimes are prohibited in anonymous constants under `min_const_generics`.
     /// This function will emit an error if `generic_const_exprs` is not enabled, the body identified by
     /// `body_id` is an anonymous constant and `lifetime_ref` is non-static.
-    crate fn maybe_emit_forbidden_non_static_lifetime_error(&self, lifetime_ref: &ast::Lifetime) {
+    pub(crate) fn maybe_emit_forbidden_non_static_lifetime_error(
+        &self,
+        lifetime_ref: &ast::Lifetime,
+    ) {
         let feature_active = self.r.session.features_untracked().generic_const_exprs;
         if !feature_active {
             feature_err(
@@ -1960,8 +2108,36 @@
     }
 }
 
+/// Report lifetime/lifetime shadowing as an error.
+pub fn signal_lifetime_shadowing(sess: &Session, orig: Ident, shadower: Ident) {
+    let mut err = struct_span_err!(
+        sess,
+        shadower.span,
+        E0496,
+        "lifetime name `{}` shadows a lifetime name that is already in scope",
+        orig.name,
+    );
+    err.span_label(orig.span, "first declared here");
+    err.span_label(shadower.span, format!("lifetime `{}` already in scope", orig.name));
+    err.emit();
+}
+
+/// Shadowing involving a label is only a warning for historical reasons.
+//FIXME: make this a proper lint.
+pub fn signal_label_shadowing(sess: &Session, orig: Span, shadower: Ident) {
+    let name = shadower.name;
+    let shadower = shadower.span;
+    let mut err = sess.struct_span_warn(
+        shadower,
+        &format!("label name `{}` shadows a label name that is already in scope", name),
+    );
+    err.span_label(orig, "first declared here");
+    err.span_label(shadower, format!("label `{}` already in scope", name));
+    err.emit();
+}
+
 impl<'tcx> LifetimeContext<'_, 'tcx> {
-    crate fn report_missing_lifetime_specifiers(
+    pub(crate) fn report_missing_lifetime_specifiers(
         &self,
         spans: Vec<Span>,
         count: usize,
@@ -1976,8 +2152,8 @@
     }
 
     /// Returns whether to add `'static` lifetime to the suggested lifetime list.
-    crate fn report_elision_failure(
-        &mut self,
+    pub(crate) fn report_elision_failure(
+        &self,
         diag: &mut Diagnostic,
         params: &[ElisionFailureInfo],
     ) -> bool {
@@ -2054,7 +2230,10 @@
         }
     }
 
-    crate fn is_trait_ref_fn_scope(&mut self, trait_ref: &'tcx hir::PolyTraitRef<'tcx>) -> bool {
+    pub(crate) fn is_trait_ref_fn_scope(
+        &mut self,
+        trait_ref: &'tcx hir::PolyTraitRef<'tcx>,
+    ) -> bool {
         if let def::Res::Def(_, did) = trait_ref.trait_ref.path.res {
             if [
                 self.tcx.lang_items().fn_once_trait(),
@@ -2063,9 +2242,18 @@
             ]
             .contains(&Some(did))
             {
-                let (span, span_type) = match &trait_ref.bound_generic_params {
-                    [] => (trait_ref.span.shrink_to_lo(), ForLifetimeSpanType::BoundEmpty),
-                    [.., bound] => (bound.span.shrink_to_hi(), ForLifetimeSpanType::BoundTail),
+                let (span, span_type) = if let Some(bound) =
+                    trait_ref.bound_generic_params.iter().rfind(|param| {
+                        matches!(
+                            param.kind,
+                            hir::GenericParamKind::Lifetime {
+                                kind: hir::LifetimeParamKind::Explicit
+                            }
+                        )
+                    }) {
+                    (bound.span.shrink_to_hi(), ForLifetimeSpanType::BoundTail)
+                } else {
+                    (trait_ref.span.shrink_to_lo(), ForLifetimeSpanType::BoundEmpty)
                 };
                 self.missing_named_lifetime_spots
                     .push(MissingLifetimeSpot::HigherRanked { span, span_type });
@@ -2075,14 +2263,31 @@
         false
     }
 
-    crate fn add_missing_lifetime_specifiers_label(
+    pub(crate) fn add_missing_lifetime_specifiers_label(
         &self,
         err: &mut Diagnostic,
         mut spans_with_counts: Vec<(Span, usize)>,
-        lifetime_names: &FxHashSet<Symbol>,
-        lifetime_spans: Vec<Span>,
-        params: &[ElisionFailureInfo],
+        in_scope_lifetimes: FxIndexSet<LocalDefId>,
+        params: Option<&[ElisionFailureInfo]>,
     ) {
+        let (mut lifetime_names, lifetime_spans): (FxHashSet<_>, Vec<_>) = in_scope_lifetimes
+            .iter()
+            .filter_map(|def_id| {
+                let name = self.tcx.item_name(def_id.to_def_id());
+                let span = self.tcx.def_ident_span(def_id.to_def_id())?;
+                Some((name, span))
+            })
+            .filter(|&(n, _)| n != kw::UnderscoreLifetime)
+            .unzip();
+
+        if let Some(params) = params {
+            // If there's no lifetime available, suggest `'static`.
+            if self.report_elision_failure(err, params) && lifetime_names.is_empty() {
+                lifetime_names.insert(kw::StaticLifetime);
+            }
+        }
+        let params = params.unwrap_or(&[]);
+
         let snippets: Vec<Option<String>> = spans_with_counts
             .iter()
             .map(|(span, _)| self.tcx.sess.source_map().span_to_snippet(*span).ok())
diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs
index ff75e4e..557dbec 100644
--- a/compiler/rustc_resolve/src/late/lifetimes.rs
+++ b/compiler/rustc_resolve/src/late/lifetimes.rs
@@ -8,42 +8,31 @@
 
 use crate::late::diagnostics::{ForLifetimeSpanType, MissingLifetimeSpot};
 use rustc_ast::walk_list;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
-use rustc_errors::{struct_span_err, Applicability, Diagnostic};
+use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
+use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{DefIdMap, LocalDefId};
-use rustc_hir::hir_id::ItemLocalId;
 use rustc_hir::intravisit::{self, Visitor};
-use rustc_hir::{GenericArg, GenericParam, LifetimeName, Node, ParamName, QPath};
-use rustc_hir::{GenericParamKind, HirIdMap, HirIdSet};
+use rustc_hir::{GenericArg, GenericParam, LifetimeName, Node};
+use rustc_hir::{GenericParamKind, HirIdMap};
 use rustc_middle::hir::map::Map;
 use rustc_middle::hir::nested_filter;
 use rustc_middle::middle::resolve_lifetime::*;
-use rustc_middle::ty::{self, DefIdTree, GenericParamDefKind, TyCtxt};
+use rustc_middle::ty::{self, GenericParamDefKind, TyCtxt};
 use rustc_middle::{bug, span_bug};
-use rustc_session::lint;
 use rustc_span::def_id::DefId;
-use rustc_span::symbol::{kw, sym, Ident, Symbol};
+use rustc_span::symbol::{kw, sym, Ident};
 use rustc_span::Span;
 use std::borrow::Cow;
 use std::cell::Cell;
 use std::fmt;
 use std::mem::take;
 
-use tracing::{debug, span, Level};
-
-// This counts the no of times a lifetime is used
-#[derive(Clone, Copy, Debug)]
-pub enum LifetimeUseSet<'tcx> {
-    One(&'tcx hir::Lifetime),
-    Many,
-}
-
 trait RegionExt {
-    fn early(hir_map: Map<'_>, index: &mut u32, param: &GenericParam<'_>) -> (ParamName, Region);
+    fn early(hir_map: Map<'_>, index: &mut u32, param: &GenericParam<'_>) -> (LocalDefId, Region);
 
-    fn late(index: u32, hir_map: Map<'_>, param: &GenericParam<'_>) -> (ParamName, Region);
+    fn late(index: u32, hir_map: Map<'_>, param: &GenericParam<'_>) -> (LocalDefId, Region);
 
     fn late_anon(named_late_bound_vars: u32, index: &Cell<u32>) -> Region;
 
@@ -59,22 +48,22 @@
 }
 
 impl RegionExt for Region {
-    fn early(hir_map: Map<'_>, index: &mut u32, param: &GenericParam<'_>) -> (ParamName, Region) {
+    fn early(hir_map: Map<'_>, index: &mut u32, param: &GenericParam<'_>) -> (LocalDefId, Region) {
         let i = *index;
         *index += 1;
         let def_id = hir_map.local_def_id(param.hir_id);
         debug!("Region::early: index={} def_id={:?}", i, def_id);
-        (param.name.normalize_to_macros_2_0(), Region::EarlyBound(i, def_id.to_def_id()))
+        (def_id, Region::EarlyBound(i, def_id.to_def_id()))
     }
 
-    fn late(idx: u32, hir_map: Map<'_>, param: &GenericParam<'_>) -> (ParamName, Region) {
+    fn late(idx: u32, hir_map: Map<'_>, param: &GenericParam<'_>) -> (LocalDefId, Region) {
         let depth = ty::INNERMOST;
         let def_id = hir_map.local_def_id(param.hir_id);
         debug!(
             "Region::late: idx={:?}, param={:?} depth={:?} def_id={:?}",
             idx, param, depth, def_id,
         );
-        (param.name.normalize_to_macros_2_0(), Region::LateBound(depth, idx, def_id.to_def_id()))
+        (def_id, Region::LateBound(depth, idx, def_id.to_def_id()))
     }
 
     fn late_anon(named_late_bound_vars: u32, index: &Cell<u32>) -> Region {
@@ -142,11 +131,6 @@
     // `Region` describing how that region is bound
     defs: HirIdMap<Region>,
 
-    // the set of lifetime def ids that are late-bound; a region can
-    // be late-bound if (a) it does NOT appear in a where-clause and
-    // (b) it DOES appear in the arguments.
-    late_bound: HirIdSet,
-
     // Maps relevant hir items to the bound vars on them. These include:
     // - function defs
     // - function pointers
@@ -154,13 +138,10 @@
     // - trait refs
     // - bound types (like `T` in `for<'a> T<'a>: Foo`)
     late_bound_vars: HirIdMap<Vec<ty::BoundVariableKind>>,
-
-    // maps `PathSegment` `HirId`s to lifetime scopes.
-    scope_for_path: Option<FxHashMap<LocalDefId, FxHashMap<ItemLocalId, LifetimeScopeForPath>>>,
 }
 
-crate struct LifetimeContext<'a, 'tcx> {
-    crate tcx: TyCtxt<'tcx>,
+pub(crate) struct LifetimeContext<'a, 'tcx> {
+    pub(crate) tcx: TyCtxt<'tcx>,
     map: &'a mut NamedRegionMap,
     scope: ScopeRef<'a>,
 
@@ -169,17 +150,12 @@
     /// we eventually need lifetimes resolve for trait items.
     trait_definition_only: bool,
 
-    /// List of labels in the function/method currently under analysis.
-    labels_in_fn: Vec<Ident>,
-
     /// Cache for cross-crate per-definition object lifetime defaults.
     xcrate_object_lifetime_defaults: DefIdMap<Vec<ObjectLifetimeDefault>>,
 
-    lifetime_uses: &'a mut DefIdMap<LifetimeUseSet<'tcx>>,
-
     /// When encountering an undefined named lifetime, we will suggest introducing it in these
     /// places.
-    crate missing_named_lifetime_spots: Vec<MissingLifetimeSpot<'tcx>>,
+    pub(crate) missing_named_lifetime_spots: Vec<MissingLifetimeSpot<'tcx>>,
 }
 
 #[derive(Debug)]
@@ -191,17 +167,12 @@
     Binder {
         /// We use an IndexMap here because we want these lifetimes in order
         /// for diagnostics.
-        lifetimes: FxIndexMap<hir::ParamName, Region>,
+        lifetimes: FxIndexMap<LocalDefId, Region>,
 
         /// if we extend this scope with another scope, what is the next index
         /// we should use for an early-bound region?
         next_early_index: u32,
 
-        /// Flag is set to true if, in this binder, `'_` would be
-        /// equivalent to a "single-use region". This is true on
-        /// impls, but not other kinds of items.
-        track_lifetime_uses: bool,
-
         /// Whether or not this binder would serve as the parent
         /// binder for opaque types introduced within. For example:
         ///
@@ -304,7 +275,6 @@
             Scope::Binder {
                 lifetimes,
                 next_early_index,
-                track_lifetime_uses,
                 opaque_type_parent,
                 scope_type,
                 hir_id,
@@ -315,7 +285,6 @@
                 .debug_struct("Binder")
                 .field("lifetimes", lifetimes)
                 .field("next_early_index", next_early_index)
-                .field("track_lifetime_uses", track_lifetime_uses)
                 .field("opaque_type_parent", opaque_type_parent)
                 .field("scope_type", scope_type)
                 .field("hir_id", hir_id)
@@ -361,14 +330,14 @@
 }
 
 #[derive(Clone, Debug)]
-crate struct ElisionFailureInfo {
+pub(crate) struct ElisionFailureInfo {
     /// Where we can find the argument pattern.
-    crate parent: Option<hir::BodyId>,
+    pub(crate) parent: Option<hir::BodyId>,
     /// The index of the argument in the original definition.
-    crate index: usize,
-    crate lifetime_count: usize,
-    crate have_bound_regions: bool,
-    crate span: Span,
+    pub(crate) index: usize,
+    pub(crate) lifetime_count: usize,
+    pub(crate) have_bound_regions: bool,
+    pub(crate) span: Span,
 }
 
 type ScopeRef<'a> = &'a Scope<'a>;
@@ -387,10 +356,6 @@
             _ => None,
         },
         late_bound_vars_map: |tcx, id| resolve_lifetimes_for(tcx, id).late_bound_vars.get(&id),
-        lifetime_scope_map: |tcx, id| {
-            let item_id = item_for(tcx, id);
-            do_resolve(tcx, item_id, false, true).scope_for_path.unwrap().remove(&id)
-        },
 
         ..*providers
     };
@@ -431,7 +396,7 @@
     tcx: TyCtxt<'_>,
     local_def_id: LocalDefId,
 ) -> ResolveLifetimes {
-    convert_named_region_map(tcx, do_resolve(tcx, local_def_id, true, false))
+    convert_named_region_map(do_resolve(tcx, local_def_id, true))
 }
 
 /// Computes the `ResolveLifetimes` map that contains data for an entire `Item`.
@@ -439,30 +404,23 @@
 /// `named_region_map`, `is_late_bound_map`, etc.
 #[tracing::instrument(level = "debug", skip(tcx))]
 fn resolve_lifetimes(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> ResolveLifetimes {
-    convert_named_region_map(tcx, do_resolve(tcx, local_def_id, false, false))
+    convert_named_region_map(do_resolve(tcx, local_def_id, false))
 }
 
 fn do_resolve(
     tcx: TyCtxt<'_>,
     local_def_id: LocalDefId,
     trait_definition_only: bool,
-    with_scope_for_path: bool,
 ) -> NamedRegionMap {
     let item = tcx.hir().expect_item(local_def_id);
-    let mut named_region_map = NamedRegionMap {
-        defs: Default::default(),
-        late_bound: Default::default(),
-        late_bound_vars: Default::default(),
-        scope_for_path: with_scope_for_path.then(|| Default::default()),
-    };
+    let mut named_region_map =
+        NamedRegionMap { defs: Default::default(), late_bound_vars: Default::default() };
     let mut visitor = LifetimeContext {
         tcx,
         map: &mut named_region_map,
         scope: ROOT_SCOPE,
         trait_definition_only,
-        labels_in_fn: vec![],
         xcrate_object_lifetime_defaults: Default::default(),
-        lifetime_uses: &mut Default::default(),
         missing_named_lifetime_spots: vec![],
     };
     visitor.visit_item(item);
@@ -470,18 +428,13 @@
     named_region_map
 }
 
-fn convert_named_region_map(tcx: TyCtxt<'_>, named_region_map: NamedRegionMap) -> ResolveLifetimes {
+fn convert_named_region_map(named_region_map: NamedRegionMap) -> ResolveLifetimes {
     let mut rl = ResolveLifetimes::default();
 
     for (hir_id, v) in named_region_map.defs {
         let map = rl.defs.entry(hir_id.owner).or_default();
         map.insert(hir_id.local_id, v);
     }
-    for hir_id in named_region_map.late_bound {
-        let map = rl.late_bound.entry(hir_id.owner).or_default();
-        let def_id = tcx.hir().local_def_id(hir_id);
-        map.insert(def_id);
-    }
     for (hir_id, v) in named_region_map.late_bound_vars {
         let map = rl.late_bound_vars.entry(hir_id.owner).or_default();
         map.insert(hir_id.local_id, v);
@@ -537,28 +490,6 @@
     item
 }
 
-fn is_late_bound_map<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    def_id: LocalDefId,
-) -> Option<(LocalDefId, &'tcx FxHashSet<LocalDefId>)> {
-    match tcx.def_kind(def_id) {
-        DefKind::AnonConst | DefKind::InlineConst => {
-            let mut def_id = tcx.local_parent(def_id);
-            // We search for the next outer anon const or fn here
-            // while skipping closures.
-            //
-            // Note that for `AnonConst` we still just recurse until we
-            // find a function body, but who cares :shrug:
-            while tcx.is_closure(def_id.to_def_id()) {
-                def_id = tcx.local_parent(def_id);
-            }
-
-            tcx.is_late_bound_map(def_id)
-        }
-        _ => resolve_lifetimes_for(tcx, def_id).late_bound.get(&def_id).map(|lt| (def_id, lt)),
-    }
-}
-
 /// In traits, there is an implicit `Self` type parameter which comes before the generics.
 /// We have to account for this when computing the index of the other generic parameters.
 /// This function returns whether there is such an implicit parameter defined on the given item.
@@ -579,41 +510,6 @@
     }
 }
 
-#[tracing::instrument(level = "debug")]
-fn get_lifetime_scopes_for_path(mut scope: &Scope<'_>) -> LifetimeScopeForPath {
-    let mut available_lifetimes = vec![];
-    loop {
-        match scope {
-            Scope::Binder { lifetimes, s, .. } => {
-                available_lifetimes.extend(lifetimes.keys().filter_map(|p| match p {
-                    hir::ParamName::Plain(ident) => Some(ident.name),
-                    _ => None,
-                }));
-                scope = s;
-            }
-            Scope::Body { s, .. } => {
-                scope = s;
-            }
-            Scope::Elision { elide, s } => {
-                if let Elide::Exact(_) = elide {
-                    return LifetimeScopeForPath::Elided;
-                } else {
-                    scope = s;
-                }
-            }
-            Scope::ObjectLifetimeDefault { s, .. } => {
-                scope = s;
-            }
-            Scope::Root => {
-                return LifetimeScopeForPath::NonElided(available_lifetimes);
-            }
-            Scope::Supertrait { s, .. } | Scope::TraitRefBoundary { s, .. } => {
-                scope = s;
-            }
-        }
-    }
-}
-
 impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
     /// Returns the binders in scope and the type of `Binder` that should be created for a poly trait ref.
     fn poly_trait_ref_binder_info(&mut self) -> (Vec<ty::BoundVariableKind>, BinderScopeType) {
@@ -668,54 +564,44 @@
     }
 
     fn visit_nested_body(&mut self, body: hir::BodyId) {
-        // Each body has their own set of labels, save labels.
-        let saved = take(&mut self.labels_in_fn);
         let body = self.tcx.hir().body(body);
-        extract_labels(self, body);
-        self.with(Scope::Body { id: body.id(), s: self.scope }, |_, this| {
+        self.with(Scope::Body { id: body.id(), s: self.scope }, |this| {
             this.visit_body(body);
         });
-        self.labels_in_fn = saved;
     }
 
-    fn visit_fn(
-        &mut self,
-        fk: intravisit::FnKind<'tcx>,
-        fd: &'tcx hir::FnDecl<'tcx>,
-        b: hir::BodyId,
-        s: rustc_span::Span,
-        hir_id: hir::HirId,
-    ) {
-        let name = match fk {
-            intravisit::FnKind::ItemFn(id, _, _) => id.name,
-            intravisit::FnKind::Method(id, _) => id.name,
-            intravisit::FnKind::Closure => sym::closure,
-        };
-        let name = name.as_str();
-        let span = span!(Level::DEBUG, "visit_fn", name);
-        let _enter = span.enter();
-        match fk {
-            // Any `Binders` are handled elsewhere
-            intravisit::FnKind::ItemFn(..) | intravisit::FnKind::Method(..) => {
-                intravisit::walk_fn(self, fk, fd, b, s, hir_id)
-            }
-            intravisit::FnKind::Closure => {
-                self.map.late_bound_vars.insert(hir_id, vec![]);
-                let scope = Scope::Binder {
-                    hir_id,
-                    lifetimes: FxIndexMap::default(),
-                    next_early_index: self.next_early_index(),
-                    s: self.scope,
-                    track_lifetime_uses: true,
-                    opaque_type_parent: false,
-                    scope_type: BinderScopeType::Normal,
-                    allow_late_bound: true,
-                    where_bound_origin: None,
-                };
-                self.with(scope, move |_old_scope, this| {
-                    intravisit::walk_fn(this, fk, fd, b, s, hir_id)
-                });
-            }
+    fn visit_expr(&mut self, e: &'tcx hir::Expr<'tcx>) {
+        if let hir::ExprKind::Closure { bound_generic_params, .. } = e.kind {
+            let next_early_index = self.next_early_index();
+            let (lifetimes, binders): (FxIndexMap<LocalDefId, Region>, Vec<_>) =
+                bound_generic_params
+                    .iter()
+                    .filter(|param| matches!(param.kind, GenericParamKind::Lifetime { .. }))
+                    .enumerate()
+                    .map(|(late_bound_idx, param)| {
+                        let pair = Region::late(late_bound_idx as u32, self.tcx.hir(), param);
+                        let r = late_region_as_bound_region(self.tcx, &pair.1);
+                        (pair, r)
+                    })
+                    .unzip();
+            self.map.late_bound_vars.insert(e.hir_id, binders);
+            let scope = Scope::Binder {
+                hir_id: e.hir_id,
+                lifetimes,
+                s: self.scope,
+                next_early_index,
+                opaque_type_parent: false,
+                scope_type: BinderScopeType::Normal,
+                allow_late_bound: true,
+                where_bound_origin: None,
+            };
+            self.with(scope, |this| {
+                // a closure has no bounds, so everything
+                // contained within is scoped within its binder.
+                intravisit::walk_expr(this, e)
+            });
+        } else {
+            intravisit::walk_expr(self, e)
         }
     }
 
@@ -729,9 +615,9 @@
             _ => {}
         }
         match item.kind {
-            hir::ItemKind::Fn(ref sig, ref generics, _) => {
+            hir::ItemKind::Fn(_, ref generics, _) => {
                 self.missing_named_lifetime_spots.push(generics.into());
-                self.visit_early_late(None, item.hir_id(), &sig.decl, generics, |this| {
+                self.visit_early_late(None, item.hir_id(), generics, |this| {
                     intravisit::walk_item(this, item);
                 });
                 self.missing_named_lifetime_spots.pop();
@@ -749,7 +635,7 @@
             hir::ItemKind::Static(..) | hir::ItemKind::Const(..) => {
                 // No lifetime parameters, but implied 'static.
                 let scope = Scope::Elision { elide: Elide::Exact(Region::Static), s: ROOT_SCOPE };
-                self.with(scope, |_, this| intravisit::walk_item(this, item));
+                self.with(scope, |this| intravisit::walk_item(this, item));
             }
             hir::ItemKind::OpaqueTy(hir::OpaqueTy { .. }) => {
                 // Opaque types are visited when we visit the
@@ -773,13 +659,6 @@
                                     self.map.defs.insert(hir::HirId { owner, local_id }, *region);
                                 });
                             }
-                            for (&owner, late_bound) in resolved_lifetimes.late_bound.iter() {
-                                late_bound.iter().for_each(|&id| {
-                                    let hir_id = self.tcx.local_def_id_to_hir_id(id);
-                                    debug_assert_eq!(owner, hir_id.owner);
-                                    self.map.late_bound.insert(hir_id);
-                                });
-                            }
                             for (&owner, late_bound_vars) in
                                 resolved_lifetimes.late_bound_vars.iter()
                             {
@@ -806,9 +685,6 @@
             | hir::ItemKind::Impl(hir::Impl { ref generics, .. }) => {
                 self.missing_named_lifetime_spots.push(generics.into());
 
-                // Impls permit `'_` to be used and it is equivalent to "some fresh lifetime name".
-                // This is not true for other kinds of items.
-                let track_lifetime_uses = matches!(item.kind, hir::ItemKind::Impl { .. });
                 // These kinds of items have only early-bound lifetime parameters.
                 let mut index = if sub_items_have_self_param(&item.kind) {
                     1 // Self comes before lifetimes
@@ -835,16 +711,14 @@
                     lifetimes,
                     next_early_index: index + non_lifetime_count,
                     opaque_type_parent: true,
-                    track_lifetime_uses,
                     scope_type: BinderScopeType::Normal,
                     s: ROOT_SCOPE,
                     allow_late_bound: false,
                     where_bound_origin: None,
                 };
-                self.with(scope, |old_scope, this| {
-                    this.check_lifetime_params(old_scope, &generics.params);
+                self.with(scope, |this| {
                     let scope = Scope::TraitRefBoundary { s: this.scope };
-                    this.with(scope, |_, this| {
+                    this.with(scope, |this| {
                         intravisit::walk_item(this, item);
                     });
                 });
@@ -855,8 +729,8 @@
 
     fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) {
         match item.kind {
-            hir::ForeignItemKind::Fn(ref decl, _, ref generics) => {
-                self.visit_early_late(None, item.hir_id(), decl, generics, |this| {
+            hir::ForeignItemKind::Fn(_, _, ref generics) => {
+                self.visit_early_late(None, item.hir_id(), generics, |this| {
                     intravisit::walk_foreign_item(this, item);
                 })
             }
@@ -876,7 +750,9 @@
                 let next_early_index = self.next_early_index();
                 let lifetime_span: Option<Span> =
                     c.generic_params.iter().rev().find_map(|param| match param.kind {
-                        GenericParamKind::Lifetime { .. } => Some(param.span),
+                        GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Explicit } => {
+                            Some(param.span)
+                        }
                         _ => None,
                     });
                 let (span, span_type) = if let Some(span) = lifetime_span {
@@ -886,7 +762,7 @@
                 };
                 self.missing_named_lifetime_spots
                     .push(MissingLifetimeSpot::HigherRanked { span, span_type });
-                let (lifetimes, binders): (FxIndexMap<hir::ParamName, Region>, Vec<_>) = c
+                let (lifetimes, binders): (FxIndexMap<LocalDefId, Region>, Vec<_>) = c
                     .generic_params
                     .iter()
                     .filter(|param| matches!(param.kind, GenericParamKind::Lifetime { .. }))
@@ -903,16 +779,14 @@
                     lifetimes,
                     s: self.scope,
                     next_early_index,
-                    track_lifetime_uses: true,
                     opaque_type_parent: false,
                     scope_type: BinderScopeType::Normal,
                     allow_late_bound: true,
                     where_bound_origin: None,
                 };
-                self.with(scope, |old_scope, this| {
+                self.with(scope, |this| {
                     // a bare fn has no bounds, so everything
                     // contained within is scoped within its binder.
-                    this.check_lifetime_params(old_scope, &c.generic_params);
                     intravisit::walk_ty(this, ty);
                 });
                 self.missing_named_lifetime_spots.pop();
@@ -920,7 +794,7 @@
             hir::TyKind::TraitObject(bounds, ref lifetime, _) => {
                 debug!(?bounds, ?lifetime, "TraitObject");
                 let scope = Scope::TraitRefBoundary { s: self.scope };
-                self.with(scope, |_, this| {
+                self.with(scope, |this| {
                     for bound in bounds {
                         this.visit_poly_trait_ref(bound, hir::TraitBoundModifier::None);
                     }
@@ -946,7 +820,7 @@
                         // cc #48468
                         self.resolve_elided_lifetimes(&[lifetime])
                     }
-                    LifetimeName::Param(_) | LifetimeName::Static => {
+                    LifetimeName::Param(..) | LifetimeName::Static => {
                         // If the user wrote an explicit name, use that.
                         self.visit_lifetime(lifetime);
                     }
@@ -959,7 +833,7 @@
                     lifetime: self.map.defs.get(&lifetime_ref.hir_id).cloned(),
                     s: self.scope,
                 };
-                self.with(scope, |_, this| this.visit_ty(&mt.ty));
+                self.with(scope, |this| this.visit_ty(&mt.ty));
             }
             hir::TyKind::OpaqueDef(item_id, lifetimes) => {
                 // Resolve the lifetimes in the bounds to the lifetime defs in the generics.
@@ -969,8 +843,6 @@
                 //                                      the opaque_ty generics
                 let opaque_ty = self.tcx.hir().item(item_id);
                 let (generics, bounds) = match opaque_ty.kind {
-                    // Named opaque `impl Trait` types are reached via `TyKind::Path`.
-                    // This arm is for `impl Trait` in the types of statics, constants and locals.
                     hir::ItemKind::OpaqueTy(hir::OpaqueTy {
                         origin: hir::OpaqueTyOrigin::TyAlias,
                         ..
@@ -980,16 +852,15 @@
                         // Elided lifetimes are not allowed in non-return
                         // position impl Trait
                         let scope = Scope::TraitRefBoundary { s: self.scope };
-                        self.with(scope, |_, this| {
+                        self.with(scope, |this| {
                             let scope = Scope::Elision { elide: Elide::Forbid, s: this.scope };
-                            this.with(scope, |_, this| {
+                            this.with(scope, |this| {
                                 intravisit::walk_item(this, opaque_ty);
                             })
                         });
 
                         return;
                     }
-                    // RPIT (return position impl trait)
                     hir::ItemKind::OpaqueTy(hir::OpaqueTy {
                         origin: hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..),
                         ref generics,
@@ -1064,22 +935,17 @@
                 for param in generics.params {
                     match param.kind {
                         GenericParamKind::Lifetime { .. } => {
-                            let (name, reg) = Region::early(self.tcx.hir(), &mut index, &param);
-                            let Region::EarlyBound(_, def_id) = reg else {
-                                bug!();
-                            };
-                            // We cannot predict what lifetimes are unused in opaque type.
-                            self.lifetime_uses.insert(def_id, LifetimeUseSet::Many);
+                            let (def_id, reg) = Region::early(self.tcx.hir(), &mut index, &param);
                             if let hir::ParamName::Plain(Ident {
                                 name: kw::UnderscoreLifetime,
                                 ..
-                            }) = name
+                            }) = param.name
                             {
                                 // Pick the elided lifetime "definition" if one exists
                                 // and use it to make an elision scope.
                                 elision = Some(reg);
                             } else {
-                                lifetimes.insert(name, reg);
+                                lifetimes.insert(def_id, reg);
                             }
                         }
                         GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
@@ -1093,22 +959,21 @@
                 if let Some(elision_region) = elision {
                     let scope =
                         Scope::Elision { elide: Elide::Exact(elision_region), s: self.scope };
-                    self.with(scope, |_old_scope, this| {
+                    self.with(scope, |this| {
                         let scope = Scope::Binder {
                             hir_id: ty.hir_id,
                             lifetimes,
                             next_early_index,
                             s: this.scope,
-                            track_lifetime_uses: true,
                             opaque_type_parent: false,
                             scope_type: BinderScopeType::Normal,
                             allow_late_bound: false,
                             where_bound_origin: None,
                         };
-                        this.with(scope, |_old_scope, this| {
+                        this.with(scope, |this| {
                             this.visit_generics(generics);
                             let scope = Scope::TraitRefBoundary { s: this.scope };
-                            this.with(scope, |_, this| {
+                            this.with(scope, |this| {
                                 for bound in bounds {
                                     this.visit_param_bound(bound);
                                 }
@@ -1121,15 +986,14 @@
                         lifetimes,
                         next_early_index,
                         s: self.scope,
-                        track_lifetime_uses: true,
                         opaque_type_parent: false,
                         scope_type: BinderScopeType::Normal,
                         allow_late_bound: false,
                         where_bound_origin: None,
                     };
-                    self.with(scope, |_old_scope, this| {
+                    self.with(scope, |this| {
                         let scope = Scope::TraitRefBoundary { s: this.scope };
-                        this.with(scope, |_, this| {
+                        this.with(scope, |this| {
                             this.visit_generics(generics);
                             for bound in bounds {
                                 this.visit_param_bound(bound);
@@ -1145,13 +1009,12 @@
     fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) {
         use self::hir::TraitItemKind::*;
         match trait_item.kind {
-            Fn(ref sig, _) => {
+            Fn(_, _) => {
                 self.missing_named_lifetime_spots.push((&trait_item.generics).into());
                 let tcx = self.tcx;
                 self.visit_early_late(
                     Some(tcx.hir().get_parent_item(trait_item.hir_id())),
                     trait_item.hir_id(),
-                    &sig.decl,
                     &trait_item.generics,
                     |this| intravisit::walk_trait_item(this, trait_item),
                 );
@@ -1182,16 +1045,14 @@
                     lifetimes,
                     next_early_index: index + non_lifetime_count,
                     s: self.scope,
-                    track_lifetime_uses: true,
                     opaque_type_parent: true,
                     scope_type: BinderScopeType::Normal,
                     allow_late_bound: false,
                     where_bound_origin: None,
                 };
-                self.with(scope, |old_scope, this| {
-                    this.check_lifetime_params(old_scope, &generics.params);
+                self.with(scope, |this| {
                     let scope = Scope::TraitRefBoundary { s: this.scope };
-                    this.with(scope, |_, this| {
+                    this.with(scope, |this| {
                         this.visit_generics(generics);
                         for bound in bounds {
                             this.visit_param_bound(bound);
@@ -1216,13 +1077,12 @@
     fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
         use self::hir::ImplItemKind::*;
         match impl_item.kind {
-            Fn(ref sig, _) => {
+            Fn(..) => {
                 self.missing_named_lifetime_spots.push((&impl_item.generics).into());
                 let tcx = self.tcx;
                 self.visit_early_late(
                     Some(tcx.hir().get_parent_item(impl_item.hir_id())),
                     impl_item.hir_id(),
-                    &sig.decl,
                     &impl_item.generics,
                     |this| intravisit::walk_impl_item(this, impl_item),
                 );
@@ -1234,7 +1094,7 @@
                 let mut index = self.next_early_index();
                 let mut non_lifetime_count = 0;
                 debug!("visit_ty: index = {}", index);
-                let lifetimes: FxIndexMap<hir::ParamName, Region> = generics
+                let lifetimes: FxIndexMap<LocalDefId, Region> = generics
                     .params
                     .iter()
                     .filter_map(|param| match param.kind {
@@ -1253,16 +1113,14 @@
                     lifetimes,
                     next_early_index: index + non_lifetime_count,
                     s: self.scope,
-                    track_lifetime_uses: true,
                     opaque_type_parent: true,
                     scope_type: BinderScopeType::Normal,
                     allow_late_bound: true,
                     where_bound_origin: None,
                 };
-                self.with(scope, |old_scope, this| {
-                    this.check_lifetime_params(old_scope, &generics.params);
+                self.with(scope, |this| {
                     let scope = Scope::TraitRefBoundary { s: this.scope };
-                    this.with(scope, |_, this| {
+                    this.with(scope, |this| {
                         this.visit_generics(generics);
                         this.visit_ty(ty);
                     })
@@ -1281,27 +1139,17 @@
 
     #[tracing::instrument(level = "debug", skip(self))]
     fn visit_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime) {
-        if lifetime_ref.is_elided() {
-            self.resolve_elided_lifetimes(&[lifetime_ref]);
-            return;
+        match lifetime_ref.name {
+            hir::LifetimeName::ImplicitObjectLifetimeDefault
+            | hir::LifetimeName::Implicit
+            | hir::LifetimeName::Underscore => self.resolve_elided_lifetimes(&[lifetime_ref]),
+            hir::LifetimeName::Static => self.insert_lifetime(lifetime_ref, Region::Static),
+            hir::LifetimeName::Param(param_def_id, _) => {
+                self.resolve_lifetime_ref(param_def_id, lifetime_ref)
+            }
+            // If we've already reported an error, just ignore `lifetime_ref`.
+            hir::LifetimeName::Error => {}
         }
-        if lifetime_ref.is_static() {
-            self.insert_lifetime(lifetime_ref, Region::Static);
-            return;
-        }
-        self.resolve_lifetime_ref(lifetime_ref);
-    }
-
-    fn visit_assoc_type_binding(&mut self, type_binding: &'tcx hir::TypeBinding<'_>) {
-        let scope = self.scope;
-        if let Some(scope_for_path) = self.map.scope_for_path.as_mut() {
-            // We add lifetime scope information for `Ident`s in associated type bindings and use
-            // the `HirId` of the type binding as the key in `LifetimeMap`
-            let lifetime_scope = get_lifetime_scopes_for_path(scope);
-            let map = scope_for_path.entry(type_binding.hir_id.owner).or_default();
-            map.insert(type_binding.hir_id.local_id, lifetime_scope);
-        }
-        hir::intravisit::walk_assoc_type_binding(self, type_binding);
     }
 
     fn visit_path(&mut self, path: &'tcx hir::Path<'tcx>, _: hir::HirId) {
@@ -1310,35 +1158,9 @@
             if let Some(ref args) = segment.args {
                 self.visit_segment_args(path.res, depth, args);
             }
-
-            let scope = self.scope;
-            if let Some(scope_for_path) = self.map.scope_for_path.as_mut() {
-                // Add lifetime scope information to path segment. Note we cannot call `visit_path_segment`
-                // here because that call would yield to resolution problems due to `walk_path_segment`
-                // being called, which processes the path segments generic args, which we have already
-                // processed using `visit_segment_args`.
-                let lifetime_scope = get_lifetime_scopes_for_path(scope);
-                if let Some(hir_id) = segment.hir_id {
-                    let map = scope_for_path.entry(hir_id.owner).or_default();
-                    map.insert(hir_id.local_id, lifetime_scope);
-                }
-            }
         }
     }
 
-    fn visit_path_segment(&mut self, path_span: Span, path_segment: &'tcx hir::PathSegment<'tcx>) {
-        let scope = self.scope;
-        if let Some(scope_for_path) = self.map.scope_for_path.as_mut() {
-            let lifetime_scope = get_lifetime_scopes_for_path(scope);
-            if let Some(hir_id) = path_segment.hir_id {
-                let map = scope_for_path.entry(hir_id.owner).or_default();
-                map.insert(hir_id.local_id, lifetime_scope);
-            }
-        }
-
-        intravisit::walk_path_segment(self, path_span, path_segment);
-    }
-
     fn visit_fn_decl(&mut self, fd: &'tcx hir::FnDecl<'tcx>) {
         let output = match fd.output {
             hir::FnRetTy::DefaultReturn(_) => None,
@@ -1349,7 +1171,7 @@
 
     fn visit_generics(&mut self, generics: &'tcx hir::Generics<'tcx>) {
         let scope = Scope::TraitRefBoundary { s: self.scope };
-        self.with(scope, |_, this| {
+        self.with(scope, |this| {
             for param in generics.params {
                 match param.kind {
                     GenericParamKind::Lifetime { .. } => {}
@@ -1375,7 +1197,7 @@
                         origin,
                         ..
                     }) => {
-                        let (lifetimes, binders): (FxIndexMap<hir::ParamName, Region>, Vec<_>) =
+                        let (lifetimes, binders): (FxIndexMap<LocalDefId, Region>, Vec<_>) =
                             bound_generic_params
                                 .iter()
                                 .filter(|param| {
@@ -1400,14 +1222,12 @@
                             lifetimes,
                             s: this.scope,
                             next_early_index,
-                            track_lifetime_uses: true,
                             opaque_type_parent: false,
                             scope_type: BinderScopeType::Normal,
                             allow_late_bound: true,
                             where_bound_origin: Some(origin),
                         };
-                        this.with(scope, |old_scope, this| {
-                            this.check_lifetime_params(old_scope, &bound_generic_params);
+                        this.with(scope, |this| {
                             this.visit_ty(&bounded_ty);
                             walk_list!(this, visit_param_bound, bounds);
                         })
@@ -1475,13 +1295,12 @@
                     lifetimes: FxIndexMap::default(),
                     s: self.scope,
                     next_early_index: self.next_early_index(),
-                    track_lifetime_uses: true,
                     opaque_type_parent: false,
                     scope_type,
                     allow_late_bound: true,
                     where_bound_origin: None,
                 };
-                self.with(scope, |_, this| {
+                self.with(scope, |this| {
                     intravisit::walk_param_bound(this, bound);
                 });
             }
@@ -1502,7 +1321,7 @@
         let (mut binders, scope_type) = self.poly_trait_ref_binder_info();
 
         let initial_bound_vars = binders.len() as u32;
-        let mut lifetimes: FxIndexMap<hir::ParamName, Region> = FxIndexMap::default();
+        let mut lifetimes: FxIndexMap<LocalDefId, Region> = FxIndexMap::default();
         let binders_iter = trait_ref
             .bound_generic_params
             .iter()
@@ -1529,14 +1348,12 @@
             lifetimes,
             s: self.scope,
             next_early_index,
-            track_lifetime_uses: true,
             opaque_type_parent: false,
             scope_type,
             allow_late_bound: true,
             where_bound_origin: None,
         };
-        self.with(scope, |old_scope, this| {
-            this.check_lifetime_params(old_scope, &trait_ref.bound_generic_params);
+        self.with(scope, |this| {
             walk_list!(this, visit_generic_param, trait_ref.bound_generic_params);
             this.visit_trait_ref(&trait_ref.trait_ref);
         });
@@ -1547,154 +1364,6 @@
     }
 }
 
-#[derive(Copy, Clone, PartialEq)]
-enum ShadowKind {
-    Label,
-    Lifetime,
-}
-struct Original {
-    kind: ShadowKind,
-    span: Span,
-}
-struct Shadower {
-    kind: ShadowKind,
-    span: Span,
-}
-
-fn original_label(span: Span) -> Original {
-    Original { kind: ShadowKind::Label, span }
-}
-fn shadower_label(span: Span) -> Shadower {
-    Shadower { kind: ShadowKind::Label, span }
-}
-fn original_lifetime(span: Span) -> Original {
-    Original { kind: ShadowKind::Lifetime, span }
-}
-fn shadower_lifetime(param: &hir::GenericParam<'_>) -> Shadower {
-    Shadower { kind: ShadowKind::Lifetime, span: param.span }
-}
-
-impl ShadowKind {
-    fn desc(&self) -> &'static str {
-        match *self {
-            ShadowKind::Label => "label",
-            ShadowKind::Lifetime => "lifetime",
-        }
-    }
-}
-
-fn signal_shadowing_problem(tcx: TyCtxt<'_>, name: Symbol, orig: Original, shadower: Shadower) {
-    let mut err = if let (ShadowKind::Lifetime, ShadowKind::Lifetime) = (orig.kind, shadower.kind) {
-        // lifetime/lifetime shadowing is an error
-        struct_span_err!(
-            tcx.sess,
-            shadower.span,
-            E0496,
-            "{} name `{}` shadows a \
-             {} name that is already in scope",
-            shadower.kind.desc(),
-            name,
-            orig.kind.desc()
-        )
-        .forget_guarantee()
-    } else {
-        // shadowing involving a label is only a warning, due to issues with
-        // labels and lifetimes not being macro-hygienic.
-        tcx.sess.struct_span_warn(
-            shadower.span,
-            &format!(
-                "{} name `{}` shadows a \
-                 {} name that is already in scope",
-                shadower.kind.desc(),
-                name,
-                orig.kind.desc()
-            ),
-        )
-    };
-    err.span_label(orig.span, "first declared here");
-    err.span_label(shadower.span, format!("{} `{}` already in scope", orig.kind.desc(), name));
-    err.emit();
-}
-
-// Adds all labels in `b` to `ctxt.labels_in_fn`, signalling a warning
-// if one of the label shadows a lifetime or another label.
-fn extract_labels(ctxt: &mut LifetimeContext<'_, '_>, body: &hir::Body<'_>) {
-    struct GatherLabels<'a, 'tcx> {
-        tcx: TyCtxt<'tcx>,
-        scope: ScopeRef<'a>,
-        labels_in_fn: &'a mut Vec<Ident>,
-    }
-
-    let mut gather =
-        GatherLabels { tcx: ctxt.tcx, scope: ctxt.scope, labels_in_fn: &mut ctxt.labels_in_fn };
-    gather.visit_body(body);
-
-    impl<'v, 'a, 'tcx> Visitor<'v> for GatherLabels<'a, 'tcx> {
-        fn visit_expr(&mut self, ex: &hir::Expr<'_>) {
-            if let Some(label) = expression_label(ex) {
-                for prior_label in &self.labels_in_fn[..] {
-                    // FIXME (#24278): non-hygienic comparison
-                    if label.name == prior_label.name {
-                        signal_shadowing_problem(
-                            self.tcx,
-                            label.name,
-                            original_label(prior_label.span),
-                            shadower_label(label.span),
-                        );
-                    }
-                }
-
-                check_if_label_shadows_lifetime(self.tcx, self.scope, label);
-
-                self.labels_in_fn.push(label);
-            }
-            intravisit::walk_expr(self, ex)
-        }
-    }
-
-    fn expression_label(ex: &hir::Expr<'_>) -> Option<Ident> {
-        match ex.kind {
-            hir::ExprKind::Loop(_, Some(label), ..) => Some(label.ident),
-            hir::ExprKind::Block(_, Some(label)) => Some(label.ident),
-            _ => None,
-        }
-    }
-
-    fn check_if_label_shadows_lifetime(tcx: TyCtxt<'_>, mut scope: ScopeRef<'_>, label: Ident) {
-        loop {
-            match *scope {
-                Scope::Body { s, .. }
-                | Scope::Elision { s, .. }
-                | Scope::ObjectLifetimeDefault { s, .. }
-                | Scope::Supertrait { s, .. }
-                | Scope::TraitRefBoundary { s, .. } => {
-                    scope = s;
-                }
-
-                Scope::Root => {
-                    return;
-                }
-
-                Scope::Binder { ref lifetimes, s, .. } => {
-                    // FIXME (#24278): non-hygienic comparison
-                    if let Some(def) =
-                        lifetimes.get(&hir::ParamName::Plain(label.normalize_to_macros_2_0()))
-                    {
-                        signal_shadowing_problem(
-                            tcx,
-                            label.name,
-                            original_lifetime(tcx.def_span(def.id().unwrap().expect_local())),
-                            shadower_label(label.span),
-                        );
-                        return;
-                    }
-                    scope = s;
-                }
-            }
-        }
-    }
-}
-
 fn compute_object_lifetime_defaults<'tcx>(
     tcx: TyCtxt<'tcx>,
     item: &hir::Item<'_>,
@@ -1800,14 +1469,17 @@
                             .iter()
                             .filter_map(|param| match param.kind {
                                 GenericParamKind::Lifetime { .. } => {
-                                    Some((param.hir_id, hir::LifetimeName::Param(param.name)))
+                                    let param_def_id = tcx.hir().local_def_id(param.hir_id);
+                                    Some((
+                                        param_def_id,
+                                        hir::LifetimeName::Param(param_def_id, param.name),
+                                    ))
                                 }
                                 _ => None,
                             })
                             .enumerate()
                             .find(|&(_, (_, lt_name))| lt_name == name)
-                            .map_or(Set1::Many, |(i, (id, _))| {
-                                let def_id = tcx.hir().local_def_id(id);
+                            .map_or(Set1::Many, |(i, (def_id, _))| {
                                 Set1::One(Region::EarlyBound(i as u32, def_id.to_def_id()))
                             })
                     }
@@ -1830,10 +1502,9 @@
 impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
     fn with<F>(&mut self, wrap_scope: Scope<'_>, f: F)
     where
-        F: for<'b> FnOnce(ScopeRef<'_>, &mut LifetimeContext<'b, 'tcx>),
+        F: for<'b> FnOnce(&mut LifetimeContext<'b, 'tcx>),
     {
-        let LifetimeContext { tcx, map, lifetime_uses, .. } = self;
-        let labels_in_fn = take(&mut self.labels_in_fn);
+        let LifetimeContext { tcx, map, .. } = self;
         let xcrate_object_lifetime_defaults = take(&mut self.xcrate_object_lifetime_defaults);
         let missing_named_lifetime_spots = take(&mut self.missing_named_lifetime_spots);
         let mut this = LifetimeContext {
@@ -1841,300 +1512,18 @@
             map,
             scope: &wrap_scope,
             trait_definition_only: self.trait_definition_only,
-            labels_in_fn,
             xcrate_object_lifetime_defaults,
-            lifetime_uses,
             missing_named_lifetime_spots,
         };
         let span = tracing::debug_span!("scope", scope = ?TruncatedScopeDebug(&this.scope));
         {
             let _enter = span.enter();
-            f(self.scope, &mut this);
-            if !self.trait_definition_only {
-                this.check_uses_for_lifetimes_defined_by_scope();
-            }
+            f(&mut this);
         }
-        self.labels_in_fn = this.labels_in_fn;
         self.xcrate_object_lifetime_defaults = this.xcrate_object_lifetime_defaults;
         self.missing_named_lifetime_spots = this.missing_named_lifetime_spots;
     }
 
-    /// helper method to determine the span to remove when suggesting the
-    /// deletion of a lifetime
-    fn lifetime_deletion_span(&self, name: Ident, generics: &hir::Generics<'_>) -> Option<Span> {
-        generics.params.iter().enumerate().find_map(|(i, param)| {
-            if param.name.ident() == name {
-                if generics.params.len() == 1 {
-                    // if sole lifetime, remove the entire `<>` brackets
-                    Some(generics.span)
-                } else {
-                    // if removing within `<>` brackets, we also want to
-                    // delete a leading or trailing comma as appropriate
-                    if i >= generics.params.len() - 1 {
-                        Some(generics.params[i - 1].span.shrink_to_hi().to(param.span))
-                    } else {
-                        Some(param.span.to(generics.params[i + 1].span.shrink_to_lo()))
-                    }
-                }
-            } else {
-                None
-            }
-        })
-    }
-
-    // helper method to issue suggestions from `fn rah<'a>(&'a T)` to `fn rah(&T)`
-    // or from `fn rah<'a>(T<'a>)` to `fn rah(T<'_>)`
-    fn suggest_eliding_single_use_lifetime(
-        &self,
-        err: &mut Diagnostic,
-        def_id: DefId,
-        lifetime: &hir::Lifetime,
-    ) {
-        let name = lifetime.name.ident();
-        let remove_decl = self
-            .tcx
-            .parent(def_id)
-            .as_local()
-            .and_then(|parent_def_id| self.tcx.hir().get_generics(parent_def_id))
-            .and_then(|generics| self.lifetime_deletion_span(name, generics));
-
-        let mut remove_use = None;
-        let mut elide_use = None;
-        let mut find_arg_use_span = |inputs: &[hir::Ty<'_>]| {
-            for input in inputs {
-                match input.kind {
-                    hir::TyKind::Rptr(lt, _) => {
-                        if lt.name.ident() == name {
-                            // include the trailing whitespace between the lifetime and type names
-                            let lt_through_ty_span = lifetime.span.to(input.span.shrink_to_hi());
-                            remove_use = Some(
-                                self.tcx
-                                    .sess
-                                    .source_map()
-                                    .span_until_non_whitespace(lt_through_ty_span),
-                            );
-                            break;
-                        }
-                    }
-                    hir::TyKind::Path(QPath::Resolved(_, path)) => {
-                        let last_segment = &path.segments[path.segments.len() - 1];
-                        let generics = last_segment.args();
-                        for arg in generics.args.iter() {
-                            if let GenericArg::Lifetime(lt) = arg {
-                                if lt.name.ident() == name {
-                                    elide_use = Some(lt.span);
-                                    break;
-                                }
-                            }
-                        }
-                        break;
-                    }
-                    _ => {}
-                }
-            }
-        };
-        if let Node::Lifetime(hir_lifetime) = self.tcx.hir().get(lifetime.hir_id) {
-            if let Some(parent) =
-                self.tcx.hir().find_by_def_id(self.tcx.hir().get_parent_item(hir_lifetime.hir_id))
-            {
-                match parent {
-                    Node::Item(item) => {
-                        if let hir::ItemKind::Fn(sig, _, _) = &item.kind {
-                            find_arg_use_span(sig.decl.inputs);
-                        }
-                    }
-                    Node::ImplItem(impl_item) => {
-                        if let hir::ImplItemKind::Fn(sig, _) = &impl_item.kind {
-                            find_arg_use_span(sig.decl.inputs);
-                        }
-                    }
-                    _ => {}
-                }
-            }
-        }
-
-        let msg = "elide the single-use lifetime";
-        match (remove_decl, remove_use, elide_use) {
-            (Some(decl_span), Some(use_span), None) => {
-                // if both declaration and use deletion spans start at the same
-                // place ("start at" because the latter includes trailing
-                // whitespace), then this is an in-band lifetime
-                if decl_span.shrink_to_lo() == use_span.shrink_to_lo() {
-                    err.span_suggestion(
-                        use_span,
-                        msg,
-                        String::new(),
-                        Applicability::MachineApplicable,
-                    );
-                } else {
-                    err.multipart_suggestion(
-                        msg,
-                        vec![(decl_span, String::new()), (use_span, String::new())],
-                        Applicability::MachineApplicable,
-                    );
-                }
-            }
-            (Some(decl_span), None, Some(use_span)) => {
-                err.multipart_suggestion(
-                    msg,
-                    vec![(decl_span, String::new()), (use_span, "'_".to_owned())],
-                    Applicability::MachineApplicable,
-                );
-            }
-            _ => {}
-        }
-    }
-
-    fn check_uses_for_lifetimes_defined_by_scope(&mut self) {
-        let Scope::Binder { lifetimes: defined_by, .. } = self.scope else {
-            debug!("check_uses_for_lifetimes_defined_by_scope: not in a binder scope");
-            return;
-        };
-
-        let def_ids: Vec<_> = defined_by
-            .values()
-            .flat_map(|region| match region {
-                Region::EarlyBound(_, def_id)
-                | Region::LateBound(_, _, def_id)
-                | Region::Free(_, def_id) => Some(*def_id),
-
-                Region::LateBoundAnon(..) | Region::Static => None,
-            })
-            .collect();
-
-        'lifetimes: for def_id in def_ids {
-            debug!("check_uses_for_lifetimes_defined_by_scope: def_id = {:?}", def_id);
-
-            let lifetimeuseset = self.lifetime_uses.remove(&def_id);
-
-            debug!(
-                "check_uses_for_lifetimes_defined_by_scope: lifetimeuseset = {:?}",
-                lifetimeuseset
-            );
-
-            match lifetimeuseset {
-                Some(LifetimeUseSet::One(lifetime)) => {
-                    debug!(?def_id);
-                    if let Some((id, span, name)) =
-                        match self.tcx.hir().get_by_def_id(def_id.expect_local()) {
-                            Node::Lifetime(hir_lifetime) => Some((
-                                hir_lifetime.hir_id,
-                                hir_lifetime.span,
-                                hir_lifetime.name.ident(),
-                            )),
-                            Node::GenericParam(param) => {
-                                Some((param.hir_id, param.span, param.name.ident()))
-                            }
-                            _ => None,
-                        }
-                    {
-                        debug!("id = {:?} span = {:?} name = {:?}", id, span, name);
-                        if name.name == kw::UnderscoreLifetime {
-                            continue;
-                        }
-
-                        let parent_def_id = self.tcx.parent(def_id);
-                        if let Some(def_id) = parent_def_id.as_local() {
-                            // lifetimes in `derive` expansions don't count (Issue #53738)
-                            if self.tcx.has_attr(def_id.to_def_id(), sym::automatically_derived) {
-                                continue;
-                            }
-
-                            // opaque types generated when desugaring an async function can have a single
-                            // use lifetime even if it is explicitly denied (Issue #77175)
-                            if let hir::Node::Item(hir::Item {
-                                kind: hir::ItemKind::OpaqueTy(ref opaque),
-                                ..
-                            }) = self.tcx.hir().get_by_def_id(def_id)
-                            {
-                                if !matches!(opaque.origin, hir::OpaqueTyOrigin::AsyncFn(..)) {
-                                    continue 'lifetimes;
-                                }
-                                // We want to do this only if the lifetime identifier is already defined
-                                // in the async function that generated this. Otherwise it could be
-                                // an opaque type defined by the developer and we still want this
-                                // lint to fail compilation
-                                for p in opaque.generics.params {
-                                    if defined_by.contains_key(&p.name) {
-                                        continue 'lifetimes;
-                                    }
-                                }
-                            }
-                        }
-
-                        self.tcx.struct_span_lint_hir(
-                            lint::builtin::SINGLE_USE_LIFETIMES,
-                            id,
-                            span,
-                            |lint| {
-                                let mut err = lint.build(&format!(
-                                    "lifetime parameter `{}` only used once",
-                                    name
-                                ));
-                                if span == lifetime.span {
-                                    // spans are the same for in-band lifetime declarations
-                                    err.span_label(span, "this lifetime is only used here");
-                                } else {
-                                    err.span_label(span, "this lifetime...");
-                                    err.span_label(lifetime.span, "...is used only here");
-                                }
-                                self.suggest_eliding_single_use_lifetime(
-                                    &mut err, def_id, lifetime,
-                                );
-                                err.emit();
-                            },
-                        );
-                    }
-                }
-                Some(LifetimeUseSet::Many) => {
-                    debug!("not one use lifetime");
-                }
-                None => {
-                    if let Some((id, span, name)) =
-                        match self.tcx.hir().get_by_def_id(def_id.expect_local()) {
-                            Node::Lifetime(hir_lifetime) => Some((
-                                hir_lifetime.hir_id,
-                                hir_lifetime.span,
-                                hir_lifetime.name.ident(),
-                            )),
-                            Node::GenericParam(param) => {
-                                Some((param.hir_id, param.span, param.name.ident()))
-                            }
-                            _ => None,
-                        }
-                    {
-                        debug!("id ={:?} span = {:?} name = {:?}", id, span, name);
-                        self.tcx.struct_span_lint_hir(
-                            lint::builtin::UNUSED_LIFETIMES,
-                            id,
-                            span,
-                            |lint| {
-                                let mut err = lint
-                                    .build(&format!("lifetime parameter `{}` never used", name));
-                                let parent_def_id = self.tcx.parent(def_id);
-                                if let Some(generics) =
-                                    self.tcx.hir().get_generics(parent_def_id.expect_local())
-                                {
-                                    let unused_lt_span =
-                                        self.lifetime_deletion_span(name, generics);
-                                    if let Some(span) = unused_lt_span {
-                                        err.span_suggestion(
-                                            span,
-                                            "elide the unused lifetime",
-                                            String::new(),
-                                            Applicability::MachineApplicable,
-                                        );
-                                    }
-                                }
-                                err.emit();
-                            },
-                        );
-                    }
-                }
-            }
-        }
-    }
-
     /// Visits self by adding a scope and handling recursive walk over the contents with `walk`.
     ///
     /// Handles visiting fns and methods. These are a bit complicated because we must distinguish
@@ -2157,14 +1546,11 @@
         &mut self,
         parent_id: Option<LocalDefId>,
         hir_id: hir::HirId,
-        decl: &'tcx hir::FnDecl<'tcx>,
         generics: &'tcx hir::Generics<'tcx>,
         walk: F,
     ) where
         F: for<'b, 'c> FnOnce(&'b mut LifetimeContext<'c, 'tcx>),
     {
-        insert_late_bound_lifetimes(self.map, decl, generics);
-
         // Find the start of nested early scopes, e.g., in methods.
         let mut next_early_index = 0;
         if let Some(parent_id) = parent_id {
@@ -2183,12 +1569,12 @@
 
         let mut non_lifetime_count = 0;
         let mut named_late_bound_vars = 0;
-        let lifetimes: FxIndexMap<hir::ParamName, Region> = generics
+        let lifetimes: FxIndexMap<LocalDefId, Region> = generics
             .params
             .iter()
             .filter_map(|param| match param.kind {
                 GenericParamKind::Lifetime { .. } => {
-                    if self.map.late_bound.contains(&param.hir_id) {
+                    if self.tcx.is_late_bound(param.hir_id) {
                         let late_bound_idx = named_late_bound_vars;
                         named_late_bound_vars += 1;
                         Some(Region::late(late_bound_idx, self.tcx.hir(), param))
@@ -2209,7 +1595,7 @@
             .iter()
             .filter(|param| {
                 matches!(param.kind, GenericParamKind::Lifetime { .. })
-                    && self.map.late_bound.contains(&param.hir_id)
+                    && self.tcx.is_late_bound(param.hir_id)
             })
             .enumerate()
             .map(|(late_bound_idx, param)| {
@@ -2224,15 +1610,11 @@
             next_early_index,
             s: self.scope,
             opaque_type_parent: true,
-            track_lifetime_uses: false,
             scope_type: BinderScopeType::Normal,
             allow_late_bound: true,
             where_bound_origin: None,
         };
-        self.with(scope, move |old_scope, this| {
-            this.check_lifetime_params(old_scope, &generics.params);
-            walk(this);
-        });
+        self.with(scope, walk);
     }
 
     fn next_early_index_helper(&self, only_opaque_type_parent: bool) -> u32 {
@@ -2271,14 +1653,12 @@
         self.next_early_index_helper(false)
     }
 
-    fn resolve_lifetime_ref(&mut self, lifetime_ref: &'tcx hir::Lifetime) {
-        debug!("resolve_lifetime_ref(lifetime_ref={:?})", lifetime_ref);
-
-        // If we've already reported an error, just ignore `lifetime_ref`.
-        if let LifetimeName::Error = lifetime_ref.name {
-            return;
-        }
-
+    #[tracing::instrument(level = "debug", skip(self))]
+    fn resolve_lifetime_ref(
+        &mut self,
+        region_def_id: LocalDefId,
+        lifetime_ref: &'tcx hir::Lifetime,
+    ) {
         // Walk up the scope chain, tracking the number of fn scopes
         // that we pass through, until we find a lifetime with the
         // given name or we run out of scopes.
@@ -2298,14 +1678,8 @@
                 }
 
                 Scope::Binder { ref lifetimes, scope_type, s, .. } => {
-                    match lifetime_ref.name {
-                        LifetimeName::Param(param_name) => {
-                            if let Some(&def) = lifetimes.get(&param_name.normalize_to_macros_2_0())
-                            {
-                                break Some(def.shifted(late_depth));
-                            }
-                        }
-                        _ => bug!("expected LifetimeName::Param"),
+                    if let Some(&def) = lifetimes.get(&region_def_id) {
+                        break Some(def.shifted(late_depth));
                     }
                     match scope_type {
                         BinderScopeType::Normal => late_depth += 1,
@@ -2360,13 +1734,12 @@
                 Scope::Binder {
                     where_bound_origin: Some(hir::PredicateOrigin::ImplTrait), ..
                 } => {
-                    self.tcx
-                        .sess
-                        .struct_span_err(
-                            lifetime_ref.span,
-                            "`impl Trait` can only mention lifetimes bound at the fn or impl level",
-                        )
-                        .emit();
+                    let mut err = self.tcx.sess.struct_span_err(
+                        lifetime_ref.span,
+                        "`impl Trait` can only mention lifetimes bound at the fn or impl level",
+                    );
+                    err.span_note(self.tcx.def_span(region_def_id), "lifetime declared here");
+                    err.emit();
                     return;
                 }
                 Scope::Root => break,
@@ -2540,7 +1913,7 @@
                 GenericArg::Type(ty) => {
                     if let Some(&lt) = object_lifetime_defaults.get(i) {
                         let scope = Scope::ObjectLifetimeDefault { lifetime: lt, s: self.scope };
-                        self.with(scope, |_, this| this.visit_ty(ty));
+                        self.with(scope, |this| this.visit_ty(ty));
                     } else {
                         self.visit_ty(ty);
                     }
@@ -2597,15 +1970,15 @@
                     type_def_id,
                     binding.ident,
                 );
-                self.with(scope, |_, this| {
+                self.with(scope, |this| {
                     let scope = Scope::Supertrait {
                         lifetimes: lifetimes.unwrap_or_default(),
                         s: this.scope,
                     };
-                    this.with(scope, |_, this| this.visit_assoc_type_binding(binding));
+                    this.with(scope, |this| this.visit_assoc_type_binding(binding));
                 });
             } else {
-                self.with(scope, |_, this| this.visit_assoc_type_binding(binding));
+                self.with(scope, |this| this.visit_assoc_type_binding(binding));
             }
         }
     }
@@ -2721,7 +2094,7 @@
             elide: Elide::FreshLateAnon(named_late_bound_vars, Cell::new(0)),
             s: self.scope,
         };
-        self.with(arg_scope, |_, this| {
+        self.with(arg_scope, |this| {
             for input in inputs {
                 this.visit_ty(input);
             }
@@ -2766,6 +2139,9 @@
 
             // Foreign functions, `fn(...) -> R` and `Trait(...) -> R` (both types and bounds).
             Node::ForeignItem(_) | Node::Ty(_) | Node::TraitRef(_) => None,
+
+            Node::TypeBinding(_) if let Node::TraitRef(_) = self.tcx.hir().get(self.tcx.hir().get_parent_node(parent)) => None,
+
             // Everything else (only closures?) doesn't
             // actually enjoy elision in return types.
             _ => {
@@ -2841,7 +2217,7 @@
             visitor.visit_ty(&inputs[0]);
             if let Set1::One(lifetime) = visitor.lifetime {
                 let scope = Scope::Elision { elide: Elide::Exact(lifetime), s: self.scope };
-                self.with(scope, |_, this| this.visit_ty(output));
+                self.with(scope, |this| this.visit_ty(output));
                 return;
             }
         }
@@ -2892,7 +2268,7 @@
         debug!(?elide);
 
         let scope = Scope::Elision { elide, s: self.scope };
-        self.with(scope, |_, this| this.visit_ty(output));
+        self.with(scope, |this| this.visit_ty(output));
 
         struct GatherLifetimes<'a> {
             map: &'a NamedRegionMap,
@@ -3018,8 +2394,7 @@
 
         let mut late_depth = 0;
         let mut scope = self.scope;
-        let mut lifetime_names = FxHashSet::default();
-        let mut lifetime_spans = vec![];
+        let mut in_scope_lifetimes = FxIndexSet::default();
         let error = loop {
             match *scope {
                 // Do not assign any resolution, it will be inferred.
@@ -3029,12 +2404,7 @@
 
                 Scope::Binder { s, ref lifetimes, scope_type, .. } => {
                     // collect named lifetimes for suggestions
-                    for name in lifetimes.keys() {
-                        if let hir::ParamName::Plain(name) = name {
-                            lifetime_names.insert(name.name);
-                            lifetime_spans.push(name.span);
-                        }
-                    }
+                    in_scope_lifetimes.extend(lifetimes.keys().copied());
                     match scope_type {
                         BinderScopeType::Normal => late_depth += 1,
                         BinderScopeType::Concatenating => {}
@@ -3069,12 +2439,7 @@
                         match scope {
                             Scope::Binder { ref lifetimes, s, .. } => {
                                 // Collect named lifetimes for suggestions.
-                                for name in lifetimes.keys() {
-                                    if let hir::ParamName::Plain(name) = name {
-                                        lifetime_names.insert(name.name);
-                                        lifetime_spans.push(name.span);
-                                    }
-                                }
+                                in_scope_lifetimes.extend(lifetimes.keys().copied());
                                 scope = s;
                             }
                             Scope::ObjectLifetimeDefault { ref s, .. }
@@ -3098,16 +2463,6 @@
             }
         };
 
-        // If we specifically need the `scope_for_path` map, then we're in the
-        // diagnostic pass and we don't want to emit more errors.
-        if self.map.scope_for_path.is_some() {
-            self.tcx.sess.delay_span_bug(
-                rustc_span::DUMMY_SP,
-                "Encountered unexpected errors during diagnostics related part",
-            );
-            return;
-        }
-
         let mut spans: Vec<_> = lifetime_refs.iter().map(|lt| lt.span).collect();
         spans.sort();
         let mut spans_dedup = spans.clone();
@@ -3119,19 +2474,11 @@
 
         let mut err = self.report_missing_lifetime_specifiers(spans.clone(), lifetime_refs.len());
 
-        if let Some(params) = error {
-            // If there's no lifetime available, suggest `'static`.
-            if self.report_elision_failure(&mut err, params) && lifetime_names.is_empty() {
-                lifetime_names.insert(kw::StaticLifetime);
-            }
-        }
-
         self.add_missing_lifetime_specifiers_label(
             &mut err,
             spans_with_counts,
-            &lifetime_names,
-            lifetime_spans,
-            error.unwrap_or(&[]),
+            in_scope_lifetimes,
+            error,
         );
         err.emit();
     }
@@ -3164,136 +2511,6 @@
         self.insert_lifetime(lifetime_ref, lifetime.shifted(late_depth));
     }
 
-    fn check_lifetime_params(
-        &mut self,
-        old_scope: ScopeRef<'_>,
-        params: &'tcx [hir::GenericParam<'tcx>],
-    ) {
-        let lifetimes: Vec<_> = params
-            .iter()
-            .filter_map(|param| match param.kind {
-                GenericParamKind::Lifetime { .. } => {
-                    Some((param, param.name.normalize_to_macros_2_0()))
-                }
-                _ => None,
-            })
-            .collect();
-        for (i, (lifetime_i, lifetime_i_name)) in lifetimes.iter().enumerate() {
-            if let hir::ParamName::Plain(_) = lifetime_i_name {
-                let name = lifetime_i_name.ident().name;
-                if name == kw::UnderscoreLifetime || name == kw::StaticLifetime {
-                    self.tcx.sess.delay_span_bug(
-                        lifetime_i.span,
-                        &format!("invalid lifetime parameter name: `{}`", lifetime_i.name.ident()),
-                    );
-                }
-            }
-
-            // It is a hard error to shadow a lifetime within the same scope.
-            for (lifetime_j, lifetime_j_name) in lifetimes.iter().skip(i + 1) {
-                if lifetime_i_name == lifetime_j_name {
-                    struct_span_err!(
-                        self.tcx.sess,
-                        lifetime_j.span,
-                        E0263,
-                        "lifetime name `{}` declared twice in the same scope",
-                        lifetime_j.name.ident()
-                    )
-                    .span_label(lifetime_j.span, "declared twice")
-                    .span_label(lifetime_i.span, "previous declaration here")
-                    .emit();
-                }
-            }
-
-            // It is a soft error to shadow a lifetime within a parent scope.
-            self.check_lifetime_param_for_shadowing(old_scope, &lifetime_i);
-        }
-    }
-
-    fn check_lifetime_param_for_shadowing(
-        &self,
-        mut old_scope: ScopeRef<'_>,
-        param: &'tcx hir::GenericParam<'tcx>,
-    ) {
-        for label in &self.labels_in_fn {
-            // FIXME (#24278): non-hygienic comparison
-            if param.name.ident().name == label.name {
-                signal_shadowing_problem(
-                    self.tcx,
-                    label.name,
-                    original_label(label.span),
-                    shadower_lifetime(&param),
-                );
-                return;
-            }
-        }
-
-        loop {
-            match *old_scope {
-                Scope::Body { s, .. }
-                | Scope::Elision { s, .. }
-                | Scope::ObjectLifetimeDefault { s, .. }
-                | Scope::Supertrait { s, .. }
-                | Scope::TraitRefBoundary { s, .. } => {
-                    old_scope = s;
-                }
-
-                Scope::Root => {
-                    return;
-                }
-
-                Scope::Binder { ref lifetimes, s, .. } => {
-                    if let Some(&def) = lifetimes.get(&param.name.normalize_to_macros_2_0()) {
-                        signal_shadowing_problem(
-                            self.tcx,
-                            param.name.ident().name,
-                            original_lifetime(self.tcx.def_span(def.id().unwrap())),
-                            shadower_lifetime(&param),
-                        );
-                        return;
-                    }
-
-                    old_scope = s;
-                }
-            }
-        }
-    }
-
-    /// Returns `true` if, in the current scope, replacing `'_` would be
-    /// equivalent to a single-use lifetime.
-    fn track_lifetime_uses(&self) -> bool {
-        let mut scope = self.scope;
-        loop {
-            match *scope {
-                Scope::Root => break false,
-
-                // Inside of items, it depends on the kind of item.
-                Scope::Binder { track_lifetime_uses, .. } => break track_lifetime_uses,
-
-                // Inside a body, `'_` will use an inference variable,
-                // should be fine.
-                Scope::Body { .. } => break true,
-
-                // A lifetime only used in a fn argument could as well
-                // be replaced with `'_`, as that would generate a
-                // fresh name, too.
-                Scope::Elision { elide: Elide::FreshLateAnon(..), .. } => break true,
-
-                // In the return type or other such place, `'_` is not
-                // going to make a fresh name, so we cannot
-                // necessarily replace a single-use lifetime with
-                // `'_`.
-                Scope::Elision {
-                    elide: Elide::Exact(_) | Elide::Error(_) | Elide::Forbid, ..
-                } => break false,
-
-                Scope::ObjectLifetimeDefault { s, .. }
-                | Scope::Supertrait { s, .. }
-                | Scope::TraitRefBoundary { s, .. } => scope = s,
-            }
-        }
-    }
-
     #[tracing::instrument(level = "debug", skip(self))]
     fn insert_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime, def: Region) {
         debug!(
@@ -3301,27 +2518,6 @@
             span = ?self.tcx.sess.source_map().span_to_diagnostic_string(lifetime_ref.span)
         );
         self.map.defs.insert(lifetime_ref.hir_id, def);
-
-        match def {
-            Region::LateBoundAnon(..) | Region::Static => {
-                // These are anonymous lifetimes or lifetimes that are not declared.
-            }
-
-            Region::Free(_, def_id)
-            | Region::LateBound(_, _, def_id)
-            | Region::EarlyBound(_, def_id) => {
-                // A lifetime declared by the user.
-                let track_lifetime_uses = self.track_lifetime_uses();
-                debug!(?track_lifetime_uses);
-                if track_lifetime_uses && !self.lifetime_uses.contains_key(&def_id) {
-                    debug!("first use of {:?}", def_id);
-                    self.lifetime_uses.insert(def_id, LifetimeUseSet::One(lifetime_ref));
-                } else {
-                    debug!("many uses of {:?}", def_id);
-                    self.lifetime_uses.insert(def_id, LifetimeUseSet::Many);
-                }
-            }
-        }
     }
 
     /// Sometimes we resolve a lifetime, but later find that it is an
@@ -3334,7 +2530,7 @@
 }
 
 /// Detects late-bound lifetimes and inserts them into
-/// `map.late_bound`.
+/// `late_bound`.
 ///
 /// A region declared on a fn is **late-bound** if:
 /// - it is constrained by an argument type;
@@ -3343,12 +2539,13 @@
 /// "Constrained" basically means that it appears in any type but
 /// not amongst the inputs to a projection. In other words, `<&'a
 /// T as Trait<''b>>::Foo` does not constrain `'a` or `'b`.
-#[tracing::instrument(level = "debug", skip(map))]
-fn insert_late_bound_lifetimes(
-    map: &mut NamedRegionMap,
-    decl: &hir::FnDecl<'_>,
-    generics: &hir::Generics<'_>,
-) {
+fn is_late_bound_map(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<&FxIndexSet<LocalDefId>> {
+    let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
+    let decl = tcx.hir().fn_decl_by_hir_id(hir_id)?;
+    let generics = tcx.hir().get_generics(def_id)?;
+
+    let mut late_bound = FxIndexSet::default();
+
     let mut constrained_by_input = ConstrainedCollector::default();
     for arg_ty in decl.inputs {
         constrained_by_input.visit_ty(arg_ty);
@@ -3379,30 +2576,32 @@
             hir::GenericParamKind::Type { .. } | hir::GenericParamKind::Const { .. } => continue,
         }
 
-        let lt_name = hir::LifetimeName::Param(param.name.normalize_to_macros_2_0());
+        let param_def_id = tcx.hir().local_def_id(param.hir_id);
+
         // appears in the where clauses? early-bound.
-        if appears_in_where_clause.regions.contains(&lt_name) {
+        if appears_in_where_clause.regions.contains(&param_def_id) {
             continue;
         }
 
         // does not appear in the inputs, but appears in the return type? early-bound.
-        if !constrained_by_input.regions.contains(&lt_name)
-            && appears_in_output.regions.contains(&lt_name)
+        if !constrained_by_input.regions.contains(&param_def_id)
+            && appears_in_output.regions.contains(&param_def_id)
         {
             continue;
         }
 
         debug!("lifetime {:?} with id {:?} is late-bound", param.name.ident(), param.hir_id);
 
-        let inserted = map.late_bound.insert(param.hir_id);
+        let inserted = late_bound.insert(param_def_id);
         assert!(inserted, "visited lifetime {:?} twice", param.hir_id);
     }
 
-    return;
+    debug!(?late_bound);
+    return Some(tcx.arena.alloc(late_bound));
 
     #[derive(Default)]
     struct ConstrainedCollector {
-        regions: FxHashSet<hir::LifetimeName>,
+        regions: FxHashSet<LocalDefId>,
     }
 
     impl<'v> Visitor<'v> for ConstrainedCollector {
@@ -3434,18 +2633,22 @@
         }
 
         fn visit_lifetime(&mut self, lifetime_ref: &'v hir::Lifetime) {
-            self.regions.insert(lifetime_ref.name.normalize_to_macros_2_0());
+            if let hir::LifetimeName::Param(def_id, _) = lifetime_ref.name {
+                self.regions.insert(def_id);
+            }
         }
     }
 
     #[derive(Default)]
     struct AllCollector {
-        regions: FxHashSet<hir::LifetimeName>,
+        regions: FxHashSet<LocalDefId>,
     }
 
     impl<'v> Visitor<'v> for AllCollector {
         fn visit_lifetime(&mut self, lifetime_ref: &'v hir::Lifetime) {
-            self.regions.insert(lifetime_ref.name.normalize_to_macros_2_0());
+            if let hir::LifetimeName::Param(def_id, _) = lifetime_ref.name {
+                self.regions.insert(def_id);
+            }
         }
     }
 }
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index 6c0148a..5738487 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -9,12 +9,11 @@
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![feature(box_patterns)]
 #![feature(drain_filter)]
-#![feature(crate_visibility_modifier)]
 #![feature(if_let_guard)]
 #![feature(let_chains)]
 #![feature(let_else)]
 #![feature(never_type)]
-#![feature(nll)]
+#![cfg_attr(bootstrap, feature(nll))]
 #![recursion_limit = "256"]
 #![allow(rustdoc::private_intra_doc_links)]
 #![allow(rustc::potential_query_instability)]
@@ -28,17 +27,16 @@
 use rustc_ast::node_id::NodeMap;
 use rustc_ast::{self as ast, NodeId, CRATE_NODE_ID};
 use rustc_ast::{AngleBracketedArg, Crate, Expr, ExprKind, GenericArg, GenericArgs, LitKind, Path};
-use rustc_ast_lowering::{LifetimeRes, ResolverAstLowering};
-use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
+use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet};
 use rustc_data_structures::intern::Interned;
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::{Applicability, DiagnosticBuilder, ErrorGuaranteed};
 use rustc_expand::base::{DeriveResolutions, SyntaxExtension, SyntaxExtensionKind};
 use rustc_hir::def::Namespace::*;
-use rustc_hir::def::{self, CtorOf, DefKind, PartialRes};
-use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefPathHash, LocalDefId};
+use rustc_hir::def::{self, CtorOf, DefKind, LifetimeRes, PartialRes};
+use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId};
 use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE};
-use rustc_hir::definitions::{DefKey, DefPathData, Definitions};
+use rustc_hir::definitions::{DefPathData, Definitions};
 use rustc_hir::TraitCandidate;
 use rustc_index::vec::IndexVec;
 use rustc_metadata::creader::{CStore, CrateLoader};
@@ -48,7 +46,7 @@
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::{self, DefIdTree, MainDefinition, RegisteredTools, ResolverOutputs};
 use rustc_query_system::ich::StableHashingContext;
-use rustc_session::cstore::{CrateStore, MetadataLoaderDyn};
+use rustc_session::cstore::{CrateStore, CrateStoreDyn, MetadataLoaderDyn};
 use rustc_session::lint::LintBuffer;
 use rustc_session::Session;
 use rustc_span::hygiene::{ExpnId, LocalExpnId, MacroKind, SyntaxContext, Transparency};
@@ -867,6 +865,12 @@
     has_derive_copy: bool,
 }
 
+#[derive(Clone)]
+struct MacroData {
+    ext: Lrc<SyntaxExtension>,
+    macro_rules: bool,
+}
+
 /// The main resolver class.
 ///
 /// This is the visitor that walks the whole crate.
@@ -874,6 +878,10 @@
     session: &'a Session,
 
     definitions: Definitions,
+    /// Item with a given `LocalDefId` was defined during macro expansion with ID `ExpnId`.
+    expn_that_defined: FxHashMap<LocalDefId, ExpnId>,
+    /// Reference span for definitions.
+    source_span: IndexVec<LocalDefId, Span>,
 
     graph_root: Module<'a>,
 
@@ -942,7 +950,7 @@
     visibilities: FxHashMap<LocalDefId, ty::Visibility>,
     has_pub_restricted: bool,
     used_imports: FxHashSet<NodeId>,
-    maybe_unused_trait_imports: FxHashSet<LocalDefId>,
+    maybe_unused_trait_imports: FxIndexSet<LocalDefId>,
     maybe_unused_extern_crates: Vec<(LocalDefId, Span)>,
 
     /// Privacy errors are delayed until the end in order to deduplicate them.
@@ -966,7 +974,7 @@
     registered_attrs: FxHashSet<Ident>,
     registered_tools: RegisteredTools,
     macro_use_prelude: FxHashMap<Symbol, &'a NameBinding<'a>>,
-    macro_map: FxHashMap<DefId, Lrc<SyntaxExtension>>,
+    macro_map: FxHashMap<DefId, MacroData>,
     dummy_ext_bang: Lrc<SyntaxExtension>,
     dummy_ext_derive: Lrc<SyntaxExtension>,
     non_macro_attr: Lrc<SyntaxExtension>,
@@ -1122,85 +1130,15 @@
     }
 }
 
-/// This interface is used through the AST→HIR step, to embed full paths into the HIR. After that
-/// the resolver is no longer needed as all the relevant information is inline.
-impl ResolverAstLowering for Resolver<'_> {
-    fn def_key(&self, id: DefId) -> DefKey {
-        if let Some(id) = id.as_local() {
-            self.definitions.def_key(id)
-        } else {
-            self.cstore().def_key(id)
-        }
-    }
-
-    #[inline]
-    fn def_span(&self, id: LocalDefId) -> Span {
-        self.definitions.def_span(id)
-    }
-
-    fn item_generics_num_lifetimes(&self, def_id: DefId) -> usize {
-        if let Some(def_id) = def_id.as_local() {
-            self.item_generics_num_lifetimes[&def_id]
-        } else {
-            self.cstore().item_generics_num_lifetimes(def_id, self.session)
-        }
-    }
-
-    fn legacy_const_generic_args(&mut self, expr: &Expr) -> Option<Vec<usize>> {
-        self.legacy_const_generic_args(expr)
-    }
-
-    fn get_partial_res(&self, id: NodeId) -> Option<PartialRes> {
-        self.partial_res_map.get(&id).cloned()
-    }
-
-    fn get_import_res(&self, id: NodeId) -> PerNS<Option<Res>> {
-        self.import_res_map.get(&id).cloned().unwrap_or_default()
-    }
-
-    fn get_label_res(&self, id: NodeId) -> Option<NodeId> {
-        self.label_res_map.get(&id).cloned()
-    }
-
-    fn get_lifetime_res(&self, id: NodeId) -> Option<LifetimeRes> {
-        self.lifetimes_res_map.get(&id).copied()
-    }
-
-    fn take_extra_lifetime_params(&mut self, id: NodeId) -> Vec<(Ident, NodeId, LifetimeRes)> {
-        self.extra_lifetime_params_map.remove(&id).unwrap_or_default()
-    }
-
-    fn create_stable_hashing_context(&self) -> StableHashingContext<'_> {
-        StableHashingContext::new(self.session, &self.definitions, self.crate_loader.cstore())
-    }
-
-    fn definitions(&self) -> &Definitions {
-        &self.definitions
-    }
-
-    fn next_node_id(&mut self) -> NodeId {
-        self.next_node_id()
-    }
-
-    fn take_trait_map(&mut self, node: NodeId) -> Option<Vec<TraitCandidate>> {
-        self.trait_map.remove(&node)
-    }
-
+impl Resolver<'_> {
     fn opt_local_def_id(&self, node: NodeId) -> Option<LocalDefId> {
         self.node_id_to_def_id.get(&node).copied()
     }
 
-    fn local_def_id(&self, node: NodeId) -> LocalDefId {
+    pub fn local_def_id(&self, node: NodeId) -> LocalDefId {
         self.opt_local_def_id(node).unwrap_or_else(|| panic!("no entry for node id: `{:?}`", node))
     }
 
-    fn def_path_hash(&self, def_id: DefId) -> DefPathHash {
-        match def_id.as_local() {
-            Some(def_id) => self.definitions.def_path_hash(def_id),
-            None => self.cstore().def_path_hash(def_id),
-        }
-    }
-
     /// Adds a definition with a parent definition.
     fn create_def(
         &mut self,
@@ -1218,7 +1156,17 @@
             self.definitions.def_key(self.node_id_to_def_id[&node_id]),
         );
 
-        let def_id = self.definitions.create_def(parent, data, expn_id, span);
+        let def_id = self.definitions.create_def(parent, data);
+
+        // Create the definition.
+        if expn_id != ExpnId::root() {
+            self.expn_that_defined.insert(def_id, expn_id);
+        }
+
+        // A relative span's parent must be an absolute span.
+        debug_assert_eq!(span.data_untracked().parent, None);
+        let _id = self.source_span.push(span);
+        debug_assert_eq!(_id, def_id);
 
         // Some things for which we allocate `LocalDefId`s don't correspond to
         // anything in the AST, so they don't have a `NodeId`. For these cases
@@ -1232,8 +1180,12 @@
         def_id
     }
 
-    fn decl_macro_kind(&self, def_id: LocalDefId) -> MacroKind {
-        self.builtin_macro_kinds.get(&def_id).copied().unwrap_or(MacroKind::Bang)
+    fn item_generics_num_lifetimes(&self, def_id: DefId) -> usize {
+        if let Some(def_id) = def_id.as_local() {
+            self.item_generics_num_lifetimes[&def_id]
+        } else {
+            self.cstore().item_generics_num_lifetimes(def_id, self.session)
+        }
     }
 }
 
@@ -1264,7 +1216,7 @@
             &mut FxHashMap::default(),
         );
 
-        let definitions = Definitions::new(session.local_stable_crate_id(), krate.spans.inner_span);
+        let definitions = Definitions::new(session.local_stable_crate_id());
 
         let mut visibilities = FxHashMap::default();
         visibilities.insert(CRATE_DEF_ID, ty::Visibility::Public);
@@ -1277,6 +1229,10 @@
         let mut invocation_parents = FxHashMap::default();
         invocation_parents.insert(LocalExpnId::ROOT, (CRATE_DEF_ID, ImplTraitContext::Existential));
 
+        let mut source_span = IndexVec::default();
+        let _id = source_span.push(krate.spans.inner_span);
+        debug_assert_eq!(_id, CRATE_DEF_ID);
+
         let mut extern_prelude: FxHashMap<Ident, ExternPreludeEntry<'_>> = session
             .opts
             .externs
@@ -1301,6 +1257,8 @@
             session,
 
             definitions,
+            expn_that_defined: Default::default(),
+            source_span,
 
             // The outermost module has def ID 0; this is not reflected in the
             // AST.
@@ -1440,9 +1398,14 @@
         Default::default()
     }
 
-    pub fn into_outputs(self) -> ResolverOutputs {
+    pub fn into_outputs(
+        self,
+    ) -> (Definitions, Box<CrateStoreDyn>, ResolverOutputs, ty::ResolverAstLowering) {
         let proc_macros = self.proc_macros.iter().map(|id| self.local_def_id(*id)).collect();
         let definitions = self.definitions;
+        let cstore = Box::new(self.crate_loader.into_cstore());
+        let source_span = self.source_span;
+        let expn_that_defined = self.expn_that_defined;
         let visibilities = self.visibilities;
         let has_pub_restricted = self.has_pub_restricted;
         let extern_crate_map = self.extern_crate_map;
@@ -1453,9 +1416,9 @@
         let main_def = self.main_def;
         let confused_type_with_std_module = self.confused_type_with_std_module;
         let access_levels = self.access_levels;
-        ResolverOutputs {
-            definitions,
-            cstore: Box::new(self.crate_loader.into_cstore()),
+        let resolutions = ResolverOutputs {
+            source_span,
+            expn_that_defined,
             visibilities,
             has_pub_restricted,
             access_levels,
@@ -1474,15 +1437,32 @@
             proc_macros,
             confused_type_with_std_module,
             registered_tools: self.registered_tools,
-        }
+        };
+        let resolutions_lowering = ty::ResolverAstLowering {
+            legacy_const_generic_args: self.legacy_const_generic_args,
+            partial_res_map: self.partial_res_map,
+            import_res_map: self.import_res_map,
+            label_res_map: self.label_res_map,
+            lifetimes_res_map: self.lifetimes_res_map,
+            extra_lifetime_params_map: self.extra_lifetime_params_map,
+            next_node_id: self.next_node_id,
+            node_id_to_def_id: self.node_id_to_def_id,
+            def_id_to_node_id: self.def_id_to_node_id,
+            trait_map: self.trait_map,
+            builtin_macro_kinds: self.builtin_macro_kinds,
+        };
+        (definitions, cstore, resolutions, resolutions_lowering)
     }
 
-    pub fn clone_outputs(&self) -> ResolverOutputs {
+    pub fn clone_outputs(
+        &self,
+    ) -> (Definitions, Box<CrateStoreDyn>, ResolverOutputs, ty::ResolverAstLowering) {
         let proc_macros = self.proc_macros.iter().map(|id| self.local_def_id(*id)).collect();
-        ResolverOutputs {
-            definitions: self.definitions.clone(),
-            access_levels: self.access_levels.clone(),
-            cstore: Box::new(self.cstore().clone()),
+        let definitions = self.definitions.clone();
+        let cstore = Box::new(self.cstore().clone());
+        let resolutions = ResolverOutputs {
+            source_span: self.source_span.clone(),
+            expn_that_defined: self.expn_that_defined.clone(),
             visibilities: self.visibilities.clone(),
             has_pub_restricted: self.has_pub_restricted,
             extern_crate_map: self.extern_crate_map.clone(),
@@ -1500,7 +1480,31 @@
             proc_macros,
             confused_type_with_std_module: self.confused_type_with_std_module.clone(),
             registered_tools: self.registered_tools.clone(),
-        }
+            access_levels: self.access_levels.clone(),
+        };
+        let resolutions_lowering = ty::ResolverAstLowering {
+            legacy_const_generic_args: self.legacy_const_generic_args.clone(),
+            partial_res_map: self.partial_res_map.clone(),
+            import_res_map: self.import_res_map.clone(),
+            label_res_map: self.label_res_map.clone(),
+            lifetimes_res_map: self.lifetimes_res_map.clone(),
+            extra_lifetime_params_map: self.extra_lifetime_params_map.clone(),
+            next_node_id: self.next_node_id.clone(),
+            node_id_to_def_id: self.node_id_to_def_id.clone(),
+            def_id_to_node_id: self.def_id_to_node_id.clone(),
+            trait_map: self.trait_map.clone(),
+            builtin_macro_kinds: self.builtin_macro_kinds.clone(),
+        };
+        (definitions, cstore, resolutions, resolutions_lowering)
+    }
+
+    fn create_stable_hashing_context(&self) -> StableHashingContext<'_> {
+        StableHashingContext::new(
+            self.session,
+            &self.definitions,
+            self.crate_loader.cstore(),
+            &self.source_span,
+        )
     }
 
     pub fn cstore(&self) -> &CStore {
@@ -1523,7 +1527,7 @@
     }
 
     fn is_builtin_macro(&mut self, res: Res) -> bool {
-        self.get_macro(res).map_or(false, |ext| ext.builtin_name.is_some())
+        self.get_macro(res).map_or(false, |macro_data| macro_data.ext.builtin_name.is_some())
     }
 
     fn macro_def(&self, mut ctxt: SyntaxContext) -> DefId {
@@ -1931,7 +1935,7 @@
     /// Retrieves the span of the given `DefId` if `DefId` is in the local crate.
     #[inline]
     pub fn opt_span(&self, def_id: DefId) -> Option<Span> {
-        def_id.as_local().map(|def_id| self.definitions.def_span(def_id))
+        def_id.as_local().map(|def_id| self.source_span[def_id])
     }
 
     /// Checks if an expression refers to a function marked with
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index 2337f72..4210560 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -7,7 +7,6 @@
 use crate::{DeriveData, Finalize, ParentScope, ResolutionError, Resolver, ScopeSet};
 use crate::{ModuleKind, ModuleOrUniformRoot, NameBinding, PathResult, Segment};
 use rustc_ast::{self as ast, Inline, ItemKind, ModKind, NodeId};
-use rustc_ast_lowering::ResolverAstLowering;
 use rustc_ast_pretty::pprust;
 use rustc_attr::StabilityLevel;
 use rustc_data_structures::fx::FxHashSet;
@@ -41,10 +40,10 @@
 /// Not modularized, can shadow previous `macro_rules` bindings, etc.
 #[derive(Debug)]
 pub struct MacroRulesBinding<'a> {
-    crate binding: &'a NameBinding<'a>,
+    pub(crate) binding: &'a NameBinding<'a>,
     /// `macro_rules` scope into which the `macro_rules` item was planted.
-    crate parent_macro_rules_scope: MacroRulesScopeRef<'a>,
-    crate ident: Ident,
+    pub(crate) parent_macro_rules_scope: MacroRulesScopeRef<'a>,
+    pub(crate) ident: Ident,
 }
 
 /// The scope introduced by a `macro_rules!` macro.
@@ -74,7 +73,10 @@
 /// Macro namespace is separated into two sub-namespaces, one for bang macros and
 /// one for attribute-like macros (attributes, derives).
 /// We ignore resolutions from one sub-namespace when searching names in scope for another.
-crate fn sub_namespace_match(candidate: Option<MacroKind>, requirement: Option<MacroKind>) -> bool {
+pub(crate) fn sub_namespace_match(
+    candidate: Option<MacroKind>,
+    requirement: Option<MacroKind>,
+) -> bool {
     #[derive(PartialEq)]
     enum SubNS {
         Bang,
@@ -140,7 +142,7 @@
     registered
 }
 
-crate fn registered_attrs_and_tools(
+pub(crate) fn registered_attrs_and_tools(
     sess: &Session,
     attrs: &[ast::Attribute],
 ) -> (FxHashSet<Ident>, FxHashSet<Ident>) {
@@ -440,11 +442,22 @@
                 PathResult::NonModule(partial_res) if partial_res.unresolved_segments() == 0 => {
                     return Ok(true);
                 }
+                PathResult::NonModule(..) |
+                // HACK(Urgau): This shouldn't be necessary
+                PathResult::Failed { is_error_from_last_segment: false, .. } => {
+                    self.session
+                        .struct_span_err(span, "not sure whether the path is accessible or not")
+                        .note("the type may have associated items, but we are currently not checking them")
+                        .emit();
+
+                    // If we get a partially resolved NonModule in one namespace, we should get the
+                    // same result in any other namespaces, so we can return early.
+                    return Ok(false);
+                }
                 PathResult::Indeterminate => indeterminate = true,
-                // FIXME: `resolve_path` is not ready to report partially resolved paths
-                // correctly, so we just report an error if the path was reported as unresolved.
-                // This needs to be fixed for `cfg_accessible` to be useful.
-                PathResult::NonModule(..) | PathResult::Failed { .. } => {}
+                // We can only be sure that a path doesn't exist after having tested all the
+                // posibilities, only at that time we can return false.
+                PathResult::Failed { .. } => {}
                 PathResult::Module(_) => panic!("unexpected path resolution"),
             }
         }
@@ -453,10 +466,6 @@
             return Err(Indeterminate);
         }
 
-        self.session
-            .struct_span_err(span, "not sure whether the path is accessible or not")
-            .span_note(span, "`cfg_accessible` is not fully implemented")
-            .emit();
         Ok(false)
     }
 
@@ -648,10 +657,10 @@
             res
         };
 
-        res.map(|res| (self.get_macro(res), res))
+        res.map(|res| (self.get_macro(res).map(|macro_data| macro_data.ext), res))
     }
 
-    crate fn finalize_macro_resolutions(&mut self) {
+    pub(crate) fn finalize_macro_resolutions(&mut self) {
         let check_consistency = |this: &mut Self,
                                  path: &[Segment],
                                  span,
@@ -839,11 +848,11 @@
         }
     }
 
-    crate fn check_reserved_macro_name(&mut self, ident: Ident, res: Res) {
+    pub(crate) fn check_reserved_macro_name(&mut self, ident: Ident, res: Res) {
         // Reserve some names that are not quite covered by the general check
         // performed on `Resolver::builtin_attrs`.
         if ident.name == sym::cfg || ident.name == sym::cfg_attr {
-            let macro_kind = self.get_macro(res).map(|ext| ext.macro_kind());
+            let macro_kind = self.get_macro(res).map(|macro_data| macro_data.ext.macro_kind());
             if macro_kind.is_some() && sub_namespace_match(macro_kind, Some(MacroKind::Attr)) {
                 self.session.span_err(
                     ident.span,
@@ -856,11 +865,11 @@
     /// Compile the macro into a `SyntaxExtension` and its rule spans.
     ///
     /// Possibly replace its expander to a pre-defined one for built-in macros.
-    crate fn compile_macro(
+    pub(crate) fn compile_macro(
         &mut self,
         item: &ast::Item,
         edition: Edition,
-    ) -> (SyntaxExtension, Vec<Span>) {
+    ) -> (SyntaxExtension, Vec<(usize, Span)>) {
         let (mut result, mut rule_spans) = compile_declarative_macro(
             &self.session,
             self.session.features_untracked(),
diff --git a/compiler/rustc_save_analysis/src/dump_visitor.rs b/compiler/rustc_save_analysis/src/dump_visitor.rs
index fe417f4..6eb2f2d 100644
--- a/compiler/rustc_save_analysis/src/dump_visitor.rs
+++ b/compiler/rustc_save_analysis/src/dump_visitor.rs
@@ -1360,15 +1360,15 @@
                     }
                 }
             }
-            hir::ExprKind::Closure(_, ref decl, body, _fn_decl_span, _) => {
+            hir::ExprKind::Closure { ref fn_decl, body, .. } => {
                 let id = format!("${}", ex.hir_id);
 
                 // walk arg and return types
-                for ty in decl.inputs {
+                for ty in fn_decl.inputs {
                     self.visit_ty(ty);
                 }
 
-                if let hir::FnRetTy::Return(ref ret_ty) = decl.output {
+                if let hir::FnRetTy::Return(ref ret_ty) = fn_decl.output {
                     self.visit_ty(ret_ty);
                 }
 
diff --git a/compiler/rustc_save_analysis/src/lib.rs b/compiler/rustc_save_analysis/src/lib.rs
index 5d94884..99f38b3 100644
--- a/compiler/rustc_save_analysis/src/lib.rs
+++ b/compiler/rustc_save_analysis/src/lib.rs
@@ -1,6 +1,5 @@
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![feature(if_let_guard)]
-#![feature(nll)]
 #![feature(let_else)]
 #![recursion_limit = "256"]
 #![allow(rustc::potential_query_instability)]
diff --git a/compiler/rustc_serialize/Cargo.toml b/compiler/rustc_serialize/Cargo.toml
index f6b9e17..dbc5c15 100644
--- a/compiler/rustc_serialize/Cargo.toml
+++ b/compiler/rustc_serialize/Cargo.toml
@@ -4,8 +4,8 @@
 edition = "2021"
 
 [dependencies]
-indexmap = "1.8.0"
-smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
+indexmap = "1.9.1"
+smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
 
 [dev-dependencies]
 rustc_macros = { path = "../rustc_macros" }
diff --git a/compiler/rustc_serialize/src/collection_impls.rs b/compiler/rustc_serialize/src/collection_impls.rs
index dee6dc0..5e53f0b 100644
--- a/compiler/rustc_serialize/src/collection_impls.rs
+++ b/compiler/rustc_serialize/src/collection_impls.rs
@@ -10,9 +10,9 @@
 use smallvec::{Array, SmallVec};
 
 impl<S: Encoder, A: Array<Item: Encodable<S>>> Encodable<S> for SmallVec<A> {
-    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
+    fn encode(&self, s: &mut S) {
         let slice: &[A::Item] = self;
-        slice.encode(s)
+        slice.encode(s);
     }
 }
 
@@ -24,13 +24,11 @@
 }
 
 impl<S: Encoder, T: Encodable<S>> Encodable<S> for LinkedList<T> {
-    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
-        s.emit_seq(self.len(), |s| {
-            for (i, e) in self.iter().enumerate() {
-                s.emit_seq_elt(i, |s| e.encode(s))?;
-            }
-            Ok(())
-        })
+    fn encode(&self, s: &mut S) {
+        s.emit_usize(self.len());
+        for e in self.iter() {
+            e.encode(s);
+        }
     }
 }
 
@@ -42,13 +40,11 @@
 }
 
 impl<S: Encoder, T: Encodable<S>> Encodable<S> for VecDeque<T> {
-    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
-        s.emit_seq(self.len(), |s| {
-            for (i, e) in self.iter().enumerate() {
-                s.emit_seq_elt(i, |s| e.encode(s))?;
-            }
-            Ok(())
-        })
+    fn encode(&self, s: &mut S) {
+        s.emit_usize(self.len());
+        for e in self.iter() {
+            e.encode(s);
+        }
     }
 }
 
@@ -64,14 +60,12 @@
     K: Encodable<S> + PartialEq + Ord,
     V: Encodable<S>,
 {
-    fn encode(&self, e: &mut S) -> Result<(), S::Error> {
-        e.emit_map(self.len(), |e| {
-            for (i, (key, val)) in self.iter().enumerate() {
-                e.emit_map_elt_key(i, |e| key.encode(e))?;
-                e.emit_map_elt_val(|e| val.encode(e))?;
-            }
-            Ok(())
-        })
+    fn encode(&self, e: &mut S) {
+        e.emit_usize(self.len());
+        for (key, val) in self.iter() {
+            key.encode(e);
+            val.encode(e);
+        }
     }
 }
 
@@ -96,13 +90,11 @@
 where
     T: Encodable<S> + PartialEq + Ord,
 {
-    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
-        s.emit_seq(self.len(), |s| {
-            for (i, e) in self.iter().enumerate() {
-                s.emit_seq_elt(i, |s| e.encode(s))?;
-            }
-            Ok(())
-        })
+    fn encode(&self, s: &mut S) {
+        s.emit_usize(self.len());
+        for e in self.iter() {
+            e.encode(s);
+        }
     }
 }
 
@@ -126,14 +118,12 @@
     V: Encodable<E>,
     S: BuildHasher,
 {
-    fn encode(&self, e: &mut E) -> Result<(), E::Error> {
-        e.emit_map(self.len(), |e| {
-            for (i, (key, val)) in self.iter().enumerate() {
-                e.emit_map_elt_key(i, |e| key.encode(e))?;
-                e.emit_map_elt_val(|e| val.encode(e))?;
-            }
-            Ok(())
-        })
+    fn encode(&self, e: &mut E) {
+        e.emit_usize(self.len());
+        for (key, val) in self.iter() {
+            key.encode(e);
+            val.encode(e);
+        }
     }
 }
 
@@ -161,23 +151,11 @@
     T: Encodable<E> + Eq,
     S: BuildHasher,
 {
-    fn encode(&self, s: &mut E) -> Result<(), E::Error> {
-        s.emit_seq(self.len(), |s| {
-            for (i, e) in self.iter().enumerate() {
-                s.emit_seq_elt(i, |s| e.encode(s))?;
-            }
-            Ok(())
-        })
-    }
-}
-
-impl<E: Encoder, T, S> Encodable<E> for &HashSet<T, S>
-where
-    T: Encodable<E> + Eq,
-    S: BuildHasher,
-{
-    fn encode(&self, s: &mut E) -> Result<(), E::Error> {
-        (**self).encode(s)
+    fn encode(&self, s: &mut E) {
+        s.emit_usize(self.len());
+        for e in self.iter() {
+            e.encode(s);
+        }
     }
 }
 
@@ -203,14 +181,12 @@
     V: Encodable<E>,
     S: BuildHasher,
 {
-    fn encode(&self, e: &mut E) -> Result<(), E::Error> {
-        e.emit_map(self.len(), |e| {
-            for (i, (key, val)) in self.iter().enumerate() {
-                e.emit_map_elt_key(i, |e| key.encode(e))?;
-                e.emit_map_elt_val(|e| val.encode(e))?;
-            }
-            Ok(())
-        })
+    fn encode(&self, e: &mut E) {
+        e.emit_usize(self.len());
+        for (key, val) in self.iter() {
+            key.encode(e);
+            val.encode(e);
+        }
     }
 }
 
@@ -238,13 +214,11 @@
     T: Encodable<E> + Hash + Eq,
     S: BuildHasher,
 {
-    fn encode(&self, s: &mut E) -> Result<(), E::Error> {
-        s.emit_seq(self.len(), |s| {
-            for (i, e) in self.iter().enumerate() {
-                s.emit_seq_elt(i, |s| e.encode(s))?;
-            }
-            Ok(())
-        })
+    fn encode(&self, s: &mut E) {
+        s.emit_usize(self.len());
+        for e in self.iter() {
+            e.encode(s);
+        }
     }
 }
 
@@ -265,9 +239,9 @@
 }
 
 impl<E: Encoder, T: Encodable<E>> Encodable<E> for Rc<[T]> {
-    fn encode(&self, s: &mut E) -> Result<(), E::Error> {
+    fn encode(&self, s: &mut E) {
         let slice: &[T] = self;
-        slice.encode(s)
+        slice.encode(s);
     }
 }
 
@@ -279,9 +253,9 @@
 }
 
 impl<E: Encoder, T: Encodable<E>> Encodable<E> for Arc<[T]> {
-    fn encode(&self, s: &mut E) -> Result<(), E::Error> {
+    fn encode(&self, s: &mut E) {
         let slice: &[T] = self;
-        slice.encode(s)
+        slice.encode(s);
     }
 }
 
diff --git a/compiler/rustc_serialize/src/json.rs b/compiler/rustc_serialize/src/json.rs
deleted file mode 100644
index c915dd5..0000000
--- a/compiler/rustc_serialize/src/json.rs
+++ /dev/null
@@ -1,2368 +0,0 @@
-// Rust JSON serialization library.
-// Copyright (c) 2011 Google Inc.
-
-#![forbid(non_camel_case_types)]
-#![allow(missing_docs)]
-
-//! JSON parsing and serialization
-//!
-//! # What is JSON?
-//!
-//! JSON (JavaScript Object Notation) is a way to write data in Javascript.
-//! Like XML, it allows to encode structured data in a text format that can be easily read by humans
-//! Its simple syntax and native compatibility with JavaScript have made it a widely used format.
-//!
-//! Data types that can be encoded are JavaScript types (see the `Json` enum for more details):
-//!
-//! * `Boolean`: equivalent to rust's `bool`
-//! * `Number`: equivalent to rust's `f64`
-//! * `String`: equivalent to rust's `String`
-//! * `Array`: equivalent to rust's `Vec<T>`, but also allowing objects of different types in the
-//!   same array
-//! * `Object`: equivalent to rust's `BTreeMap<String, json::Json>`
-//! * `Null`
-//!
-//! An object is a series of string keys mapping to values, in `"key": value` format.
-//! Arrays are enclosed in square brackets ([ ... ]) and objects in curly brackets ({ ... }).
-//! A simple JSON document encoding a person, their age, address and phone numbers could look like
-//!
-//! ```json
-//! {
-//!     "FirstName": "John",
-//!     "LastName": "Doe",
-//!     "Age": 43,
-//!     "Address": {
-//!         "Street": "Downing Street 10",
-//!         "City": "London",
-//!         "Country": "Great Britain"
-//!     },
-//!     "PhoneNumbers": [
-//!         "+44 1234567",
-//!         "+44 2345678"
-//!     ]
-//! }
-//! ```
-//!
-//! # Rust Type-based Encoding and Decoding
-//!
-//! To be able to encode a piece of data, it must implement the
-//! `serialize::Encodable` trait.  The `rustc_macros` crate provides an
-//! annotation to automatically generate the code for this trait: `#[derive(Encodable)]`.
-//!
-//! The JSON API provides an enum `json::Json` and a trait `ToJson` to encode objects.
-//! The `ToJson` trait provides a `to_json` method to convert an object into a `json::Json` value.
-//! A `json::Json` value can be encoded as a string or buffer using the functions described above.
-//! You can also use the `json::Encoder` object, which implements the `Encoder` trait.
-//!
-//! When using `ToJson` the `Encodable` trait implementation is not mandatory.
-//!
-//! # Examples of use
-//!
-//! ## Using Autoserialization
-//!
-//! Create a struct called `TestStruct` and serialize and deserialize it to and from JSON using the
-//! serialization API, using the derived serialization code.
-//!
-//! ```rust
-//! # #![feature(rustc_private)]
-//! use rustc_macros::{Encodable};
-//! use rustc_serialize::json;
-//!
-//! // Automatically generate `Encodable` trait implementations
-//! #[derive(Encodable)]
-//! pub struct TestStruct  {
-//!     data_int: u8,
-//!     data_str: String,
-//!     data_vector: Vec<u8>,
-//! }
-//!
-//! let object = TestStruct {
-//!     data_int: 1,
-//!     data_str: "homura".to_string(),
-//!     data_vector: vec![2,3,4,5],
-//! };
-//!
-//! // Serialize using `json::encode`
-//! let encoded = json::encode(&object).unwrap();
-//! ```
-//!
-//! ## Using the `ToJson` trait
-//!
-//! The examples above use the `ToJson` trait to generate the JSON string, which is required
-//! for custom mappings.
-//!
-//! ### Simple example of `ToJson` usage
-//!
-//! ```rust
-//! # #![feature(rustc_private)]
-//! use rustc_macros::Encodable;
-//! use rustc_serialize::json::{self, ToJson, Json};
-//!
-//! // A custom data structure
-//! struct ComplexNum {
-//!     a: f64,
-//!     b: f64,
-//! }
-//!
-//! // JSON value representation
-//! impl ToJson for ComplexNum {
-//!     fn to_json(&self) -> Json {
-//!         Json::String(format!("{}+{}i", self.a, self.b))
-//!     }
-//! }
-//!
-//! // Only generate `Encodable` trait implementation
-//! #[derive(Encodable)]
-//! pub struct ComplexNumRecord {
-//!     uid: u8,
-//!     dsc: String,
-//!     val: Json,
-//! }
-//!
-//! let num = ComplexNum { a: 0.0001, b: 12.539 };
-//! let data: String = json::encode(&ComplexNumRecord{
-//!     uid: 1,
-//!     dsc: "test".to_string(),
-//!     val: num.to_json(),
-//! }).unwrap();
-//! println!("data: {}", data);
-//! // data: {"uid":1,"dsc":"test","val":"0.0001+12.539i"};
-//! ```
-//!
-//! ### Verbose example of `ToJson` usage
-//!
-//! ```rust
-//! # #![feature(rustc_private)]
-//! use std::collections::BTreeMap;
-//! use rustc_serialize::json::{Json, ToJson};
-//!
-//! pub struct TestStruct {
-//!     data_int: u8,
-//!     data_str: String,
-//!     data_vector: Vec<u8>,
-//! }
-//!
-//! // Specify encoding method manually
-//! impl ToJson for TestStruct {
-//!     fn to_json(&self) -> Json {
-//!         let mut d = BTreeMap::new();
-//!         // All standard types implement `to_json()`, so use it
-//!         d.insert("data_int".to_string(), self.data_int.to_json());
-//!         d.insert("data_str".to_string(), self.data_str.to_json());
-//!         d.insert("data_vector".to_string(), self.data_vector.to_json());
-//!         Json::Object(d)
-//!     }
-//! }
-//!
-//! // Serialize using `ToJson`
-//! let input_data = TestStruct {
-//!     data_int: 1,
-//!     data_str: "madoka".to_string(),
-//!     data_vector: vec![2,3,4,5],
-//! };
-//! let json_obj: Json = input_data.to_json();
-//! let json_str: String = json_obj.to_string();
-//! ```
-
-use self::ErrorCode::*;
-use self::InternalStackElement::*;
-use self::JsonEvent::*;
-use self::ParserError::*;
-use self::ParserState::*;
-
-use std::borrow::Cow;
-use std::collections::{BTreeMap, HashMap};
-use std::mem::swap;
-use std::num::FpCategory as Fp;
-use std::ops::Index;
-use std::str::FromStr;
-use std::string;
-use std::{char, fmt, str};
-
-use crate::Encodable;
-
-/// Represents a json value
-#[derive(Clone, PartialEq, PartialOrd, Debug)]
-pub enum Json {
-    I64(i64),
-    U64(u64),
-    F64(f64),
-    String(string::String),
-    Boolean(bool),
-    Array(self::Array),
-    Object(self::Object),
-    Null,
-}
-
-pub type Array = Vec<Json>;
-pub type Object = BTreeMap<string::String, Json>;
-
-pub struct PrettyJson<'a> {
-    inner: &'a Json,
-}
-
-pub struct AsJson<'a, T> {
-    inner: &'a T,
-}
-pub struct AsPrettyJson<'a, T> {
-    inner: &'a T,
-    indent: Option<usize>,
-}
-
-/// The errors that can arise while parsing a JSON stream.
-#[derive(Clone, Copy, PartialEq, Debug)]
-pub enum ErrorCode {
-    InvalidSyntax,
-    InvalidNumber,
-    EOFWhileParsingObject,
-    EOFWhileParsingArray,
-    EOFWhileParsingValue,
-    EOFWhileParsingString,
-    KeyMustBeAString,
-    ExpectedColon,
-    TrailingCharacters,
-    TrailingComma,
-    InvalidEscape,
-    InvalidUnicodeCodePoint,
-    LoneLeadingSurrogateInHexEscape,
-    UnexpectedEndOfHexEscape,
-    UnrecognizedHex,
-    NotFourDigit,
-    NotUtf8,
-}
-
-#[derive(Clone, PartialEq, Debug)]
-pub enum ParserError {
-    /// msg, line, col
-    SyntaxError(ErrorCode, usize, usize),
-}
-
-// Builder and Parser have the same errors.
-pub type BuilderError = ParserError;
-
-#[derive(Copy, Clone, Debug)]
-pub enum EncoderError {
-    FmtError(fmt::Error),
-    BadHashmapKey,
-}
-
-/// Returns a readable error string for a given error code.
-pub fn error_str(error: ErrorCode) -> &'static str {
-    match error {
-        InvalidSyntax => "invalid syntax",
-        InvalidNumber => "invalid number",
-        EOFWhileParsingObject => "EOF While parsing object",
-        EOFWhileParsingArray => "EOF While parsing array",
-        EOFWhileParsingValue => "EOF While parsing value",
-        EOFWhileParsingString => "EOF While parsing string",
-        KeyMustBeAString => "key must be a string",
-        ExpectedColon => "expected `:`",
-        TrailingCharacters => "trailing characters",
-        TrailingComma => "trailing comma",
-        InvalidEscape => "invalid escape",
-        UnrecognizedHex => "invalid \\u{ esc}ape (unrecognized hex)",
-        NotFourDigit => "invalid \\u{ esc}ape (not four digits)",
-        NotUtf8 => "contents not utf-8",
-        InvalidUnicodeCodePoint => "invalid Unicode code point",
-        LoneLeadingSurrogateInHexEscape => "lone leading surrogate in hex escape",
-        UnexpectedEndOfHexEscape => "unexpected end of hex escape",
-    }
-}
-
-/// Shortcut function to encode a `T` into a JSON `String`
-pub fn encode<T: for<'r> crate::Encodable<Encoder<'r>>>(
-    object: &T,
-) -> Result<string::String, EncoderError> {
-    let mut s = String::new();
-    {
-        let mut encoder = Encoder::new(&mut s);
-        object.encode(&mut encoder)?;
-    }
-    Ok(s)
-}
-
-impl fmt::Display for ErrorCode {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        error_str(*self).fmt(f)
-    }
-}
-
-impl fmt::Display for ParserError {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        // FIXME this should be a nicer error
-        fmt::Debug::fmt(self, f)
-    }
-}
-
-impl fmt::Display for EncoderError {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        // FIXME this should be a nicer error
-        fmt::Debug::fmt(self, f)
-    }
-}
-
-impl std::error::Error for EncoderError {}
-
-impl From<fmt::Error> for EncoderError {
-    /// Converts a [`fmt::Error`] into `EncoderError`
-    ///
-    /// This conversion does not allocate memory.
-    fn from(err: fmt::Error) -> EncoderError {
-        EncoderError::FmtError(err)
-    }
-}
-
-pub type EncodeResult = Result<(), EncoderError>;
-
-fn escape_str(wr: &mut dyn fmt::Write, v: &str) -> EncodeResult {
-    wr.write_str("\"")?;
-
-    let mut start = 0;
-
-    for (i, byte) in v.bytes().enumerate() {
-        let escaped = match byte {
-            b'"' => "\\\"",
-            b'\\' => "\\\\",
-            b'\x00' => "\\u0000",
-            b'\x01' => "\\u0001",
-            b'\x02' => "\\u0002",
-            b'\x03' => "\\u0003",
-            b'\x04' => "\\u0004",
-            b'\x05' => "\\u0005",
-            b'\x06' => "\\u0006",
-            b'\x07' => "\\u0007",
-            b'\x08' => "\\b",
-            b'\t' => "\\t",
-            b'\n' => "\\n",
-            b'\x0b' => "\\u000b",
-            b'\x0c' => "\\f",
-            b'\r' => "\\r",
-            b'\x0e' => "\\u000e",
-            b'\x0f' => "\\u000f",
-            b'\x10' => "\\u0010",
-            b'\x11' => "\\u0011",
-            b'\x12' => "\\u0012",
-            b'\x13' => "\\u0013",
-            b'\x14' => "\\u0014",
-            b'\x15' => "\\u0015",
-            b'\x16' => "\\u0016",
-            b'\x17' => "\\u0017",
-            b'\x18' => "\\u0018",
-            b'\x19' => "\\u0019",
-            b'\x1a' => "\\u001a",
-            b'\x1b' => "\\u001b",
-            b'\x1c' => "\\u001c",
-            b'\x1d' => "\\u001d",
-            b'\x1e' => "\\u001e",
-            b'\x1f' => "\\u001f",
-            b'\x7f' => "\\u007f",
-            _ => {
-                continue;
-            }
-        };
-
-        if start < i {
-            wr.write_str(&v[start..i])?;
-        }
-
-        wr.write_str(escaped)?;
-
-        start = i + 1;
-    }
-
-    if start != v.len() {
-        wr.write_str(&v[start..])?;
-    }
-
-    wr.write_str("\"")?;
-    Ok(())
-}
-
-fn escape_char(writer: &mut dyn fmt::Write, v: char) -> EncodeResult {
-    escape_str(writer, v.encode_utf8(&mut [0; 4]))
-}
-
-fn spaces(wr: &mut dyn fmt::Write, mut n: usize) -> EncodeResult {
-    const BUF: &str = "                ";
-
-    while n >= BUF.len() {
-        wr.write_str(BUF)?;
-        n -= BUF.len();
-    }
-
-    if n > 0 {
-        wr.write_str(&BUF[..n])?;
-    }
-    Ok(())
-}
-
-fn fmt_number_or_null(v: f64) -> string::String {
-    match v.classify() {
-        Fp::Nan | Fp::Infinite => string::String::from("null"),
-        _ if v.fract() != 0f64 => v.to_string(),
-        _ => v.to_string() + ".0",
-    }
-}
-
-/// A structure for implementing serialization to JSON.
-pub struct Encoder<'a> {
-    writer: &'a mut (dyn fmt::Write + 'a),
-    is_emitting_map_key: bool,
-}
-
-impl<'a> Encoder<'a> {
-    /// Creates a new JSON encoder whose output will be written to the writer
-    /// specified.
-    pub fn new(writer: &'a mut dyn fmt::Write) -> Encoder<'a> {
-        Encoder { writer, is_emitting_map_key: false }
-    }
-}
-
-macro_rules! emit_enquoted_if_mapkey {
-    ($enc:ident,$e:expr) => {{
-        if $enc.is_emitting_map_key {
-            write!($enc.writer, "\"{}\"", $e)?;
-        } else {
-            write!($enc.writer, "{}", $e)?;
-        }
-        Ok(())
-    }};
-}
-
-impl<'a> crate::Encoder for Encoder<'a> {
-    type Error = EncoderError;
-
-    fn emit_unit(&mut self) -> EncodeResult {
-        if self.is_emitting_map_key {
-            return Err(EncoderError::BadHashmapKey);
-        }
-        write!(self.writer, "null")?;
-        Ok(())
-    }
-
-    fn emit_usize(&mut self, v: usize) -> EncodeResult {
-        emit_enquoted_if_mapkey!(self, v)
-    }
-    fn emit_u128(&mut self, v: u128) -> EncodeResult {
-        emit_enquoted_if_mapkey!(self, v)
-    }
-    fn emit_u64(&mut self, v: u64) -> EncodeResult {
-        emit_enquoted_if_mapkey!(self, v)
-    }
-    fn emit_u32(&mut self, v: u32) -> EncodeResult {
-        emit_enquoted_if_mapkey!(self, v)
-    }
-    fn emit_u16(&mut self, v: u16) -> EncodeResult {
-        emit_enquoted_if_mapkey!(self, v)
-    }
-    fn emit_u8(&mut self, v: u8) -> EncodeResult {
-        emit_enquoted_if_mapkey!(self, v)
-    }
-
-    fn emit_isize(&mut self, v: isize) -> EncodeResult {
-        emit_enquoted_if_mapkey!(self, v)
-    }
-    fn emit_i128(&mut self, v: i128) -> EncodeResult {
-        emit_enquoted_if_mapkey!(self, v)
-    }
-    fn emit_i64(&mut self, v: i64) -> EncodeResult {
-        emit_enquoted_if_mapkey!(self, v)
-    }
-    fn emit_i32(&mut self, v: i32) -> EncodeResult {
-        emit_enquoted_if_mapkey!(self, v)
-    }
-    fn emit_i16(&mut self, v: i16) -> EncodeResult {
-        emit_enquoted_if_mapkey!(self, v)
-    }
-    fn emit_i8(&mut self, v: i8) -> EncodeResult {
-        emit_enquoted_if_mapkey!(self, v)
-    }
-
-    fn emit_bool(&mut self, v: bool) -> EncodeResult {
-        if self.is_emitting_map_key {
-            return Err(EncoderError::BadHashmapKey);
-        }
-        if v {
-            write!(self.writer, "true")?;
-        } else {
-            write!(self.writer, "false")?;
-        }
-        Ok(())
-    }
-
-    fn emit_f64(&mut self, v: f64) -> EncodeResult {
-        emit_enquoted_if_mapkey!(self, fmt_number_or_null(v))
-    }
-    fn emit_f32(&mut self, v: f32) -> EncodeResult {
-        self.emit_f64(f64::from(v))
-    }
-
-    fn emit_char(&mut self, v: char) -> EncodeResult {
-        escape_char(self.writer, v)
-    }
-    fn emit_str(&mut self, v: &str) -> EncodeResult {
-        escape_str(self.writer, v)
-    }
-    fn emit_raw_bytes(&mut self, s: &[u8]) -> Result<(), Self::Error> {
-        for &c in s.iter() {
-            self.emit_u8(c)?;
-        }
-        Ok(())
-    }
-
-    fn emit_enum<F>(&mut self, f: F) -> EncodeResult
-    where
-        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
-    {
-        f(self)
-    }
-
-    fn emit_enum_variant<F>(&mut self, name: &str, _id: usize, cnt: usize, f: F) -> EncodeResult
-    where
-        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
-    {
-        // enums are encoded as strings or objects
-        // Bunny => "Bunny"
-        // Kangaroo(34,"William") => {"variant": "Kangaroo", "fields": [34,"William"]}
-        if cnt == 0 {
-            escape_str(self.writer, name)
-        } else {
-            if self.is_emitting_map_key {
-                return Err(EncoderError::BadHashmapKey);
-            }
-            write!(self.writer, "{{\"variant\":")?;
-            escape_str(self.writer, name)?;
-            write!(self.writer, ",\"fields\":[")?;
-            f(self)?;
-            write!(self.writer, "]}}")?;
-            Ok(())
-        }
-    }
-
-    fn emit_fieldless_enum_variant<const ID: usize>(
-        &mut self,
-        name: &str,
-    ) -> Result<(), Self::Error> {
-        escape_str(self.writer, name)
-    }
-
-    fn emit_enum_variant_arg<F>(&mut self, first: bool, f: F) -> EncodeResult
-    where
-        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
-    {
-        if self.is_emitting_map_key {
-            return Err(EncoderError::BadHashmapKey);
-        }
-        if !first {
-            write!(self.writer, ",")?;
-        }
-        f(self)
-    }
-
-    fn emit_struct<F>(&mut self, _: bool, f: F) -> EncodeResult
-    where
-        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
-    {
-        if self.is_emitting_map_key {
-            return Err(EncoderError::BadHashmapKey);
-        }
-        write!(self.writer, "{{")?;
-        f(self)?;
-        write!(self.writer, "}}")?;
-        Ok(())
-    }
-
-    fn emit_struct_field<F>(&mut self, name: &str, first: bool, f: F) -> EncodeResult
-    where
-        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
-    {
-        if self.is_emitting_map_key {
-            return Err(EncoderError::BadHashmapKey);
-        }
-        if !first {
-            write!(self.writer, ",")?;
-        }
-        escape_str(self.writer, name)?;
-        write!(self.writer, ":")?;
-        f(self)
-    }
-
-    fn emit_tuple<F>(&mut self, len: usize, f: F) -> EncodeResult
-    where
-        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
-    {
-        if self.is_emitting_map_key {
-            return Err(EncoderError::BadHashmapKey);
-        }
-        self.emit_seq(len, f)
-    }
-    fn emit_tuple_arg<F>(&mut self, idx: usize, f: F) -> EncodeResult
-    where
-        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
-    {
-        if self.is_emitting_map_key {
-            return Err(EncoderError::BadHashmapKey);
-        }
-        self.emit_seq_elt(idx, f)
-    }
-
-    fn emit_option<F>(&mut self, f: F) -> EncodeResult
-    where
-        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
-    {
-        if self.is_emitting_map_key {
-            return Err(EncoderError::BadHashmapKey);
-        }
-        f(self)
-    }
-    fn emit_option_none(&mut self) -> EncodeResult {
-        if self.is_emitting_map_key {
-            return Err(EncoderError::BadHashmapKey);
-        }
-        self.emit_unit()
-    }
-    fn emit_option_some<F>(&mut self, f: F) -> EncodeResult
-    where
-        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
-    {
-        if self.is_emitting_map_key {
-            return Err(EncoderError::BadHashmapKey);
-        }
-        f(self)
-    }
-
-    fn emit_seq<F>(&mut self, _len: usize, f: F) -> EncodeResult
-    where
-        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
-    {
-        if self.is_emitting_map_key {
-            return Err(EncoderError::BadHashmapKey);
-        }
-        write!(self.writer, "[")?;
-        f(self)?;
-        write!(self.writer, "]")?;
-        Ok(())
-    }
-
-    fn emit_seq_elt<F>(&mut self, idx: usize, f: F) -> EncodeResult
-    where
-        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
-    {
-        if self.is_emitting_map_key {
-            return Err(EncoderError::BadHashmapKey);
-        }
-        if idx != 0 {
-            write!(self.writer, ",")?;
-        }
-        f(self)
-    }
-
-    fn emit_map<F>(&mut self, _len: usize, f: F) -> EncodeResult
-    where
-        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
-    {
-        if self.is_emitting_map_key {
-            return Err(EncoderError::BadHashmapKey);
-        }
-        write!(self.writer, "{{")?;
-        f(self)?;
-        write!(self.writer, "}}")?;
-        Ok(())
-    }
-
-    fn emit_map_elt_key<F>(&mut self, idx: usize, f: F) -> EncodeResult
-    where
-        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
-    {
-        if self.is_emitting_map_key {
-            return Err(EncoderError::BadHashmapKey);
-        }
-        if idx != 0 {
-            write!(self.writer, ",")?
-        }
-        self.is_emitting_map_key = true;
-        f(self)?;
-        self.is_emitting_map_key = false;
-        Ok(())
-    }
-
-    fn emit_map_elt_val<F>(&mut self, f: F) -> EncodeResult
-    where
-        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
-    {
-        if self.is_emitting_map_key {
-            return Err(EncoderError::BadHashmapKey);
-        }
-        write!(self.writer, ":")?;
-        f(self)
-    }
-}
-
-/// Another encoder for JSON, but prints out human-readable JSON instead of
-/// compact data
-pub struct PrettyEncoder<'a> {
-    writer: &'a mut (dyn fmt::Write + 'a),
-    curr_indent: usize,
-    indent: usize,
-    is_emitting_map_key: bool,
-}
-
-impl<'a> PrettyEncoder<'a> {
-    /// Creates a new encoder whose output will be written to the specified writer
-    pub fn new(writer: &'a mut dyn fmt::Write) -> PrettyEncoder<'a> {
-        PrettyEncoder { writer, curr_indent: 0, indent: 2, is_emitting_map_key: false }
-    }
-
-    /// Sets the number of spaces to indent for each level.
-    /// This is safe to set during encoding.
-    pub fn set_indent(&mut self, indent: usize) {
-        // self.indent very well could be 0 so we need to use checked division.
-        let level = self.curr_indent.checked_div(self.indent).unwrap_or(0);
-        self.indent = indent;
-        self.curr_indent = level * self.indent;
-    }
-}
-
-impl<'a> crate::Encoder for PrettyEncoder<'a> {
-    type Error = EncoderError;
-
-    fn emit_unit(&mut self) -> EncodeResult {
-        if self.is_emitting_map_key {
-            return Err(EncoderError::BadHashmapKey);
-        }
-        write!(self.writer, "null")?;
-        Ok(())
-    }
-
-    fn emit_usize(&mut self, v: usize) -> EncodeResult {
-        emit_enquoted_if_mapkey!(self, v)
-    }
-    fn emit_u128(&mut self, v: u128) -> EncodeResult {
-        emit_enquoted_if_mapkey!(self, v)
-    }
-    fn emit_u64(&mut self, v: u64) -> EncodeResult {
-        emit_enquoted_if_mapkey!(self, v)
-    }
-    fn emit_u32(&mut self, v: u32) -> EncodeResult {
-        emit_enquoted_if_mapkey!(self, v)
-    }
-    fn emit_u16(&mut self, v: u16) -> EncodeResult {
-        emit_enquoted_if_mapkey!(self, v)
-    }
-    fn emit_u8(&mut self, v: u8) -> EncodeResult {
-        emit_enquoted_if_mapkey!(self, v)
-    }
-
-    fn emit_isize(&mut self, v: isize) -> EncodeResult {
-        emit_enquoted_if_mapkey!(self, v)
-    }
-    fn emit_i128(&mut self, v: i128) -> EncodeResult {
-        emit_enquoted_if_mapkey!(self, v)
-    }
-    fn emit_i64(&mut self, v: i64) -> EncodeResult {
-        emit_enquoted_if_mapkey!(self, v)
-    }
-    fn emit_i32(&mut self, v: i32) -> EncodeResult {
-        emit_enquoted_if_mapkey!(self, v)
-    }
-    fn emit_i16(&mut self, v: i16) -> EncodeResult {
-        emit_enquoted_if_mapkey!(self, v)
-    }
-    fn emit_i8(&mut self, v: i8) -> EncodeResult {
-        emit_enquoted_if_mapkey!(self, v)
-    }
-
-    fn emit_bool(&mut self, v: bool) -> EncodeResult {
-        if self.is_emitting_map_key {
-            return Err(EncoderError::BadHashmapKey);
-        }
-        if v {
-            write!(self.writer, "true")?;
-        } else {
-            write!(self.writer, "false")?;
-        }
-        Ok(())
-    }
-
-    fn emit_f64(&mut self, v: f64) -> EncodeResult {
-        emit_enquoted_if_mapkey!(self, fmt_number_or_null(v))
-    }
-    fn emit_f32(&mut self, v: f32) -> EncodeResult {
-        self.emit_f64(f64::from(v))
-    }
-
-    fn emit_char(&mut self, v: char) -> EncodeResult {
-        escape_char(self.writer, v)
-    }
-    fn emit_str(&mut self, v: &str) -> EncodeResult {
-        escape_str(self.writer, v)
-    }
-    fn emit_raw_bytes(&mut self, s: &[u8]) -> Result<(), Self::Error> {
-        for &c in s.iter() {
-            self.emit_u8(c)?;
-        }
-        Ok(())
-    }
-
-    fn emit_enum<F>(&mut self, f: F) -> EncodeResult
-    where
-        F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
-    {
-        f(self)
-    }
-
-    fn emit_enum_variant<F>(&mut self, name: &str, _id: usize, cnt: usize, f: F) -> EncodeResult
-    where
-        F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
-    {
-        if cnt == 0 {
-            escape_str(self.writer, name)
-        } else {
-            if self.is_emitting_map_key {
-                return Err(EncoderError::BadHashmapKey);
-            }
-            writeln!(self.writer, "{{")?;
-            self.curr_indent += self.indent;
-            spaces(self.writer, self.curr_indent)?;
-            write!(self.writer, "\"variant\": ")?;
-            escape_str(self.writer, name)?;
-            writeln!(self.writer, ",")?;
-            spaces(self.writer, self.curr_indent)?;
-            writeln!(self.writer, "\"fields\": [")?;
-            self.curr_indent += self.indent;
-            f(self)?;
-            self.curr_indent -= self.indent;
-            writeln!(self.writer)?;
-            spaces(self.writer, self.curr_indent)?;
-            self.curr_indent -= self.indent;
-            writeln!(self.writer, "]")?;
-            spaces(self.writer, self.curr_indent)?;
-            write!(self.writer, "}}")?;
-            Ok(())
-        }
-    }
-
-    fn emit_fieldless_enum_variant<const ID: usize>(
-        &mut self,
-        name: &str,
-    ) -> Result<(), Self::Error> {
-        escape_str(self.writer, name)
-    }
-
-    fn emit_enum_variant_arg<F>(&mut self, first: bool, f: F) -> EncodeResult
-    where
-        F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
-    {
-        if self.is_emitting_map_key {
-            return Err(EncoderError::BadHashmapKey);
-        }
-        if !first {
-            writeln!(self.writer, ",")?;
-        }
-        spaces(self.writer, self.curr_indent)?;
-        f(self)
-    }
-
-    fn emit_struct<F>(&mut self, no_fields: bool, f: F) -> EncodeResult
-    where
-        F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
-    {
-        if self.is_emitting_map_key {
-            return Err(EncoderError::BadHashmapKey);
-        }
-        if no_fields {
-            write!(self.writer, "{{}}")?;
-        } else {
-            write!(self.writer, "{{")?;
-            self.curr_indent += self.indent;
-            f(self)?;
-            self.curr_indent -= self.indent;
-            writeln!(self.writer)?;
-            spaces(self.writer, self.curr_indent)?;
-            write!(self.writer, "}}")?;
-        }
-        Ok(())
-    }
-
-    fn emit_struct_field<F>(&mut self, name: &str, first: bool, f: F) -> EncodeResult
-    where
-        F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
-    {
-        if self.is_emitting_map_key {
-            return Err(EncoderError::BadHashmapKey);
-        }
-        if first {
-            writeln!(self.writer)?;
-        } else {
-            writeln!(self.writer, ",")?;
-        }
-        spaces(self.writer, self.curr_indent)?;
-        escape_str(self.writer, name)?;
-        write!(self.writer, ": ")?;
-        f(self)
-    }
-
-    fn emit_tuple<F>(&mut self, len: usize, f: F) -> EncodeResult
-    where
-        F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
-    {
-        if self.is_emitting_map_key {
-            return Err(EncoderError::BadHashmapKey);
-        }
-        self.emit_seq(len, f)
-    }
-    fn emit_tuple_arg<F>(&mut self, idx: usize, f: F) -> EncodeResult
-    where
-        F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
-    {
-        if self.is_emitting_map_key {
-            return Err(EncoderError::BadHashmapKey);
-        }
-        self.emit_seq_elt(idx, f)
-    }
-
-    fn emit_option<F>(&mut self, f: F) -> EncodeResult
-    where
-        F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
-    {
-        if self.is_emitting_map_key {
-            return Err(EncoderError::BadHashmapKey);
-        }
-        f(self)
-    }
-    fn emit_option_none(&mut self) -> EncodeResult {
-        if self.is_emitting_map_key {
-            return Err(EncoderError::BadHashmapKey);
-        }
-        self.emit_unit()
-    }
-    fn emit_option_some<F>(&mut self, f: F) -> EncodeResult
-    where
-        F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
-    {
-        if self.is_emitting_map_key {
-            return Err(EncoderError::BadHashmapKey);
-        }
-        f(self)
-    }
-
-    fn emit_seq<F>(&mut self, len: usize, f: F) -> EncodeResult
-    where
-        F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
-    {
-        if self.is_emitting_map_key {
-            return Err(EncoderError::BadHashmapKey);
-        }
-        if len == 0 {
-            write!(self.writer, "[]")?;
-        } else {
-            write!(self.writer, "[")?;
-            self.curr_indent += self.indent;
-            f(self)?;
-            self.curr_indent -= self.indent;
-            writeln!(self.writer)?;
-            spaces(self.writer, self.curr_indent)?;
-            write!(self.writer, "]")?;
-        }
-        Ok(())
-    }
-
-    fn emit_seq_elt<F>(&mut self, idx: usize, f: F) -> EncodeResult
-    where
-        F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
-    {
-        if self.is_emitting_map_key {
-            return Err(EncoderError::BadHashmapKey);
-        }
-        if idx == 0 {
-            writeln!(self.writer)?;
-        } else {
-            writeln!(self.writer, ",")?;
-        }
-        spaces(self.writer, self.curr_indent)?;
-        f(self)
-    }
-
-    fn emit_map<F>(&mut self, len: usize, f: F) -> EncodeResult
-    where
-        F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
-    {
-        if self.is_emitting_map_key {
-            return Err(EncoderError::BadHashmapKey);
-        }
-        if len == 0 {
-            write!(self.writer, "{{}}")?;
-        } else {
-            write!(self.writer, "{{")?;
-            self.curr_indent += self.indent;
-            f(self)?;
-            self.curr_indent -= self.indent;
-            writeln!(self.writer)?;
-            spaces(self.writer, self.curr_indent)?;
-            write!(self.writer, "}}")?;
-        }
-        Ok(())
-    }
-
-    fn emit_map_elt_key<F>(&mut self, idx: usize, f: F) -> EncodeResult
-    where
-        F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
-    {
-        if self.is_emitting_map_key {
-            return Err(EncoderError::BadHashmapKey);
-        }
-        if idx == 0 {
-            writeln!(self.writer)?;
-        } else {
-            writeln!(self.writer, ",")?;
-        }
-        spaces(self.writer, self.curr_indent)?;
-        self.is_emitting_map_key = true;
-        f(self)?;
-        self.is_emitting_map_key = false;
-        Ok(())
-    }
-
-    fn emit_map_elt_val<F>(&mut self, f: F) -> EncodeResult
-    where
-        F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
-    {
-        if self.is_emitting_map_key {
-            return Err(EncoderError::BadHashmapKey);
-        }
-        write!(self.writer, ": ")?;
-        f(self)
-    }
-}
-
-impl<E: crate::Encoder> Encodable<E> for Json {
-    fn encode(&self, e: &mut E) -> Result<(), E::Error> {
-        match *self {
-            Json::I64(v) => v.encode(e),
-            Json::U64(v) => v.encode(e),
-            Json::F64(v) => v.encode(e),
-            Json::String(ref v) => v.encode(e),
-            Json::Boolean(v) => v.encode(e),
-            Json::Array(ref v) => v.encode(e),
-            Json::Object(ref v) => v.encode(e),
-            Json::Null => e.emit_unit(),
-        }
-    }
-}
-
-/// Creates an `AsJson` wrapper which can be used to print a value as JSON
-/// on-the-fly via `write!`
-pub fn as_json<T>(t: &T) -> AsJson<'_, T> {
-    AsJson { inner: t }
-}
-
-/// Creates an `AsPrettyJson` wrapper which can be used to print a value as JSON
-/// on-the-fly via `write!`
-pub fn as_pretty_json<T>(t: &T) -> AsPrettyJson<'_, T> {
-    AsPrettyJson { inner: t, indent: None }
-}
-
-impl Json {
-    /// Borrow this json object as a pretty object to generate a pretty
-    /// representation for it via `Display`.
-    pub fn pretty(&self) -> PrettyJson<'_> {
-        PrettyJson { inner: self }
-    }
-
-    /// If the Json value is an Object, returns the value associated with the provided key.
-    /// Otherwise, returns None.
-    pub fn find(&self, key: &str) -> Option<&Json> {
-        match *self {
-            Json::Object(ref map) => map.get(key),
-            _ => None,
-        }
-    }
-
-    /// If the Json value is an Object, deletes the value associated with the
-    /// provided key from the Object and returns it. Otherwise, returns None.
-    pub fn remove_key(&mut self, key: &str) -> Option<Json> {
-        match *self {
-            Json::Object(ref mut map) => map.remove(key),
-            _ => None,
-        }
-    }
-
-    /// Attempts to get a nested Json Object for each key in `keys`.
-    /// If any key is found not to exist, `find_path` will return `None`.
-    /// Otherwise, it will return the Json value associated with the final key.
-    pub fn find_path<'a>(&'a self, keys: &[&str]) -> Option<&'a Json> {
-        let mut target = self;
-        for key in keys {
-            target = target.find(*key)?;
-        }
-        Some(target)
-    }
-
-    /// If the Json value is an Object, performs a depth-first search until
-    /// a value associated with the provided key is found. If no value is found
-    /// or the Json value is not an Object, returns `None`.
-    pub fn search(&self, key: &str) -> Option<&Json> {
-        match *self {
-            Json::Object(ref map) => match map.get(key) {
-                Some(json_value) => Some(json_value),
-                None => {
-                    for v in map.values() {
-                        match v.search(key) {
-                            x if x.is_some() => return x,
-                            _ => (),
-                        }
-                    }
-                    None
-                }
-            },
-            _ => None,
-        }
-    }
-
-    /// Returns `true` if the Json value is an `Object`.
-    pub fn is_object(&self) -> bool {
-        self.as_object().is_some()
-    }
-
-    /// If the Json value is an `Object`, returns the associated `BTreeMap`;
-    /// returns `None` otherwise.
-    pub fn as_object(&self) -> Option<&Object> {
-        match *self {
-            Json::Object(ref map) => Some(map),
-            _ => None,
-        }
-    }
-
-    /// Returns `true` if the Json value is an `Array`.
-    pub fn is_array(&self) -> bool {
-        self.as_array().is_some()
-    }
-
-    /// If the Json value is an `Array`, returns the associated vector;
-    /// returns `None` otherwise.
-    pub fn as_array(&self) -> Option<&Array> {
-        match *self {
-            Json::Array(ref array) => Some(&*array),
-            _ => None,
-        }
-    }
-
-    /// Returns `true` if the Json value is a `String`.
-    pub fn is_string(&self) -> bool {
-        self.as_string().is_some()
-    }
-
-    /// If the Json value is a `String`, returns the associated `str`;
-    /// returns `None` otherwise.
-    pub fn as_string(&self) -> Option<&str> {
-        match *self {
-            Json::String(ref s) => Some(&s[..]),
-            _ => None,
-        }
-    }
-
-    /// Returns `true` if the Json value is a `Number`.
-    pub fn is_number(&self) -> bool {
-        matches!(*self, Json::I64(_) | Json::U64(_) | Json::F64(_))
-    }
-
-    /// Returns `true` if the Json value is an `i64`.
-    pub fn is_i64(&self) -> bool {
-        matches!(*self, Json::I64(_))
-    }
-
-    /// Returns `true` if the Json value is a `u64`.
-    pub fn is_u64(&self) -> bool {
-        matches!(*self, Json::U64(_))
-    }
-
-    /// Returns `true` if the Json value is a `f64`.
-    pub fn is_f64(&self) -> bool {
-        matches!(*self, Json::F64(_))
-    }
-
-    /// If the Json value is a number, returns or cast it to an `i64`;
-    /// returns `None` otherwise.
-    pub fn as_i64(&self) -> Option<i64> {
-        match *self {
-            Json::I64(n) => Some(n),
-            Json::U64(n) => Some(n as i64),
-            _ => None,
-        }
-    }
-
-    /// If the Json value is a number, returns or cast it to a `u64`;
-    /// returns `None` otherwise.
-    pub fn as_u64(&self) -> Option<u64> {
-        match *self {
-            Json::I64(n) => Some(n as u64),
-            Json::U64(n) => Some(n),
-            _ => None,
-        }
-    }
-
-    /// If the Json value is a number, returns or cast it to a `f64`;
-    /// returns `None` otherwise.
-    pub fn as_f64(&self) -> Option<f64> {
-        match *self {
-            Json::I64(n) => Some(n as f64),
-            Json::U64(n) => Some(n as f64),
-            Json::F64(n) => Some(n),
-            _ => None,
-        }
-    }
-
-    /// Returns `true` if the Json value is a `Boolean`.
-    pub fn is_boolean(&self) -> bool {
-        self.as_boolean().is_some()
-    }
-
-    /// If the Json value is a `Boolean`, returns the associated `bool`;
-    /// returns `None` otherwise.
-    pub fn as_boolean(&self) -> Option<bool> {
-        match *self {
-            Json::Boolean(b) => Some(b),
-            _ => None,
-        }
-    }
-
-    /// Returns `true` if the Json value is a `Null`.
-    pub fn is_null(&self) -> bool {
-        self.as_null().is_some()
-    }
-
-    /// If the Json value is a `Null`, returns `()`;
-    /// returns `None` otherwise.
-    pub fn as_null(&self) -> Option<()> {
-        match *self {
-            Json::Null => Some(()),
-            _ => None,
-        }
-    }
-}
-
-impl<'a> Index<&'a str> for Json {
-    type Output = Json;
-
-    fn index(&self, idx: &'a str) -> &Json {
-        self.find(idx).unwrap()
-    }
-}
-
-impl Index<usize> for Json {
-    type Output = Json;
-
-    fn index(&self, idx: usize) -> &Json {
-        match *self {
-            Json::Array(ref v) => &v[idx],
-            _ => panic!("can only index Json with usize if it is an array"),
-        }
-    }
-}
-
-/// The output of the streaming parser.
-#[derive(PartialEq, Clone, Debug)]
-pub enum JsonEvent {
-    ObjectStart,
-    ObjectEnd,
-    ArrayStart,
-    ArrayEnd,
-    BooleanValue(bool),
-    I64Value(i64),
-    U64Value(u64),
-    F64Value(f64),
-    StringValue(string::String),
-    NullValue,
-    Error(ParserError),
-}
-
-#[derive(PartialEq, Debug)]
-enum ParserState {
-    // Parse a value in an array, true means first element.
-    ParseArray(bool),
-    // Parse ',' or ']' after an element in an array.
-    ParseArrayComma,
-    // Parse a key:value in an object, true means first element.
-    ParseObject(bool),
-    // Parse ',' or ']' after an element in an object.
-    ParseObjectComma,
-    // Initial state.
-    ParseStart,
-    // Expecting the stream to end.
-    ParseBeforeFinish,
-    // Parsing can't continue.
-    ParseFinished,
-}
-
-/// A Stack represents the current position of the parser in the logical
-/// structure of the JSON stream.
-///
-/// An example is `foo.bar[3].x`.
-#[derive(Default)]
-pub struct Stack {
-    stack: Vec<InternalStackElement>,
-    str_buffer: Vec<u8>,
-}
-
-/// StackElements compose a Stack.
-///
-/// As an example, `StackElement::Key("foo")`, `StackElement::Key("bar")`,
-/// `StackElement::Index(3)`, and `StackElement::Key("x")` are the
-/// StackElements composing the stack that represents `foo.bar[3].x`.
-#[derive(PartialEq, Clone, Debug)]
-pub enum StackElement<'l> {
-    Index(u32),
-    Key(&'l str),
-}
-
-// Internally, Key elements are stored as indices in a buffer to avoid
-// allocating a string for every member of an object.
-#[derive(PartialEq, Clone, Debug)]
-enum InternalStackElement {
-    InternalIndex(u32),
-    InternalKey(u16, u16), // start, size
-}
-
-impl Stack {
-    pub fn new() -> Stack {
-        Self::default()
-    }
-
-    /// Returns The number of elements in the Stack.
-    pub fn len(&self) -> usize {
-        self.stack.len()
-    }
-
-    /// Returns `true` if the stack is empty.
-    pub fn is_empty(&self) -> bool {
-        self.stack.is_empty()
-    }
-
-    /// Provides access to the StackElement at a given index.
-    /// lower indices are at the bottom of the stack while higher indices are
-    /// at the top.
-    pub fn get(&self, idx: usize) -> StackElement<'_> {
-        match self.stack[idx] {
-            InternalIndex(i) => StackElement::Index(i),
-            InternalKey(start, size) => StackElement::Key(
-                str::from_utf8(&self.str_buffer[start as usize..start as usize + size as usize])
-                    .unwrap(),
-            ),
-        }
-    }
-
-    /// Compares this stack with an array of StackElement<'_>s.
-    pub fn is_equal_to(&self, rhs: &[StackElement<'_>]) -> bool {
-        if self.stack.len() != rhs.len() {
-            return false;
-        }
-        for (i, r) in rhs.iter().enumerate() {
-            if self.get(i) != *r {
-                return false;
-            }
-        }
-        true
-    }
-
-    /// Returns `true` if the bottom-most elements of this stack are the same as
-    /// the ones passed as parameter.
-    pub fn starts_with(&self, rhs: &[StackElement<'_>]) -> bool {
-        if self.stack.len() < rhs.len() {
-            return false;
-        }
-        for (i, r) in rhs.iter().enumerate() {
-            if self.get(i) != *r {
-                return false;
-            }
-        }
-        true
-    }
-
-    /// Returns `true` if the top-most elements of this stack are the same as
-    /// the ones passed as parameter.
-    pub fn ends_with(&self, rhs: &[StackElement<'_>]) -> bool {
-        if self.stack.len() < rhs.len() {
-            return false;
-        }
-        let offset = self.stack.len() - rhs.len();
-        for (i, r) in rhs.iter().enumerate() {
-            if self.get(i + offset) != *r {
-                return false;
-            }
-        }
-        true
-    }
-
-    /// Returns the top-most element (if any).
-    pub fn top(&self) -> Option<StackElement<'_>> {
-        match self.stack.last() {
-            None => None,
-            Some(&InternalIndex(i)) => Some(StackElement::Index(i)),
-            Some(&InternalKey(start, size)) => Some(StackElement::Key(
-                str::from_utf8(&self.str_buffer[start as usize..(start + size) as usize]).unwrap(),
-            )),
-        }
-    }
-
-    // Used by Parser to insert StackElement::Key elements at the top of the stack.
-    fn push_key(&mut self, key: string::String) {
-        self.stack.push(InternalKey(self.str_buffer.len() as u16, key.len() as u16));
-        self.str_buffer.extend(key.as_bytes());
-    }
-
-    // Used by Parser to insert StackElement::Index elements at the top of the stack.
-    fn push_index(&mut self, index: u32) {
-        self.stack.push(InternalIndex(index));
-    }
-
-    // Used by Parser to remove the top-most element of the stack.
-    fn pop(&mut self) {
-        assert!(!self.is_empty());
-        match *self.stack.last().unwrap() {
-            InternalKey(_, sz) => {
-                let new_size = self.str_buffer.len() - sz as usize;
-                self.str_buffer.truncate(new_size);
-            }
-            InternalIndex(_) => {}
-        }
-        self.stack.pop();
-    }
-
-    // Used by Parser to test whether the top-most element is an index.
-    fn last_is_index(&self) -> bool {
-        matches!(self.stack.last(), Some(InternalIndex(_)))
-    }
-
-    // Used by Parser to increment the index of the top-most element.
-    fn bump_index(&mut self) {
-        let len = self.stack.len();
-        let idx = match *self.stack.last().unwrap() {
-            InternalIndex(i) => i + 1,
-            _ => {
-                panic!();
-            }
-        };
-        self.stack[len - 1] = InternalIndex(idx);
-    }
-}
-
-/// A streaming JSON parser implemented as an iterator of JsonEvent, consuming
-/// an iterator of char.
-pub struct Parser<T> {
-    rdr: T,
-    ch: Option<char>,
-    line: usize,
-    col: usize,
-    // We maintain a stack representing where we are in the logical structure
-    // of the JSON stream.
-    stack: Stack,
-    // A state machine is kept to make it possible to interrupt and resume parsing.
-    state: ParserState,
-}
-
-impl<T: Iterator<Item = char>> Iterator for Parser<T> {
-    type Item = JsonEvent;
-
-    fn next(&mut self) -> Option<JsonEvent> {
-        if self.state == ParseFinished {
-            return None;
-        }
-
-        if self.state == ParseBeforeFinish {
-            self.parse_whitespace();
-            // Make sure there is no trailing characters.
-            if self.eof() {
-                self.state = ParseFinished;
-                return None;
-            } else {
-                return Some(self.error_event(TrailingCharacters));
-            }
-        }
-
-        Some(self.parse())
-    }
-}
-
-impl<T: Iterator<Item = char>> Parser<T> {
-    /// Creates the JSON parser.
-    pub fn new(rdr: T) -> Parser<T> {
-        let mut p = Parser {
-            rdr,
-            ch: Some('\x00'),
-            line: 1,
-            col: 0,
-            stack: Stack::new(),
-            state: ParseStart,
-        };
-        p.bump();
-        p
-    }
-
-    /// Provides access to the current position in the logical structure of the
-    /// JSON stream.
-    pub fn stack(&self) -> &Stack {
-        &self.stack
-    }
-
-    fn eof(&self) -> bool {
-        self.ch.is_none()
-    }
-    fn ch_or_null(&self) -> char {
-        self.ch.unwrap_or('\x00')
-    }
-    fn bump(&mut self) {
-        self.ch = self.rdr.next();
-
-        if self.ch_is('\n') {
-            self.line += 1;
-            self.col = 1;
-        } else {
-            self.col += 1;
-        }
-    }
-
-    fn next_char(&mut self) -> Option<char> {
-        self.bump();
-        self.ch
-    }
-    fn ch_is(&self, c: char) -> bool {
-        self.ch == Some(c)
-    }
-
-    fn error<U>(&self, reason: ErrorCode) -> Result<U, ParserError> {
-        Err(SyntaxError(reason, self.line, self.col))
-    }
-
-    fn parse_whitespace(&mut self) {
-        while self.ch_is(' ') || self.ch_is('\n') || self.ch_is('\t') || self.ch_is('\r') {
-            self.bump();
-        }
-    }
-
-    fn parse_number(&mut self) -> JsonEvent {
-        let neg = if self.ch_is('-') {
-            self.bump();
-            true
-        } else {
-            false
-        };
-
-        let res = match self.parse_u64() {
-            Ok(res) => res,
-            Err(e) => {
-                return Error(e);
-            }
-        };
-
-        if self.ch_is('.') || self.ch_is('e') || self.ch_is('E') {
-            let mut res = res as f64;
-
-            if self.ch_is('.') {
-                res = match self.parse_decimal(res) {
-                    Ok(res) => res,
-                    Err(e) => {
-                        return Error(e);
-                    }
-                };
-            }
-
-            if self.ch_is('e') || self.ch_is('E') {
-                res = match self.parse_exponent(res) {
-                    Ok(res) => res,
-                    Err(e) => {
-                        return Error(e);
-                    }
-                };
-            }
-
-            if neg {
-                res *= -1.0;
-            }
-
-            F64Value(res)
-        } else if neg {
-            let res = (res as i64).wrapping_neg();
-
-            // Make sure we didn't underflow.
-            if res > 0 {
-                Error(SyntaxError(InvalidNumber, self.line, self.col))
-            } else {
-                I64Value(res)
-            }
-        } else {
-            U64Value(res)
-        }
-    }
-
-    fn parse_u64(&mut self) -> Result<u64, ParserError> {
-        let mut accum = 0u64;
-        let last_accum = 0; // necessary to detect overflow.
-
-        match self.ch_or_null() {
-            '0' => {
-                self.bump();
-
-                // A leading '0' must be the only digit before the decimal point.
-                if let '0'..='9' = self.ch_or_null() {
-                    return self.error(InvalidNumber);
-                }
-            }
-            '1'..='9' => {
-                while !self.eof() {
-                    match self.ch_or_null() {
-                        c @ '0'..='9' => {
-                            accum = accum.wrapping_mul(10);
-                            accum = accum.wrapping_add((c as u64) - ('0' as u64));
-
-                            // Detect overflow by comparing to the last value.
-                            if accum <= last_accum {
-                                return self.error(InvalidNumber);
-                            }
-
-                            self.bump();
-                        }
-                        _ => break,
-                    }
-                }
-            }
-            _ => return self.error(InvalidNumber),
-        }
-
-        Ok(accum)
-    }
-
-    fn parse_decimal(&mut self, mut res: f64) -> Result<f64, ParserError> {
-        self.bump();
-
-        // Make sure a digit follows the decimal place.
-        match self.ch_or_null() {
-            '0'..='9' => (),
-            _ => return self.error(InvalidNumber),
-        }
-
-        let mut dec = 1.0;
-        while !self.eof() {
-            match self.ch_or_null() {
-                c @ '0'..='9' => {
-                    dec /= 10.0;
-                    res += (((c as isize) - ('0' as isize)) as f64) * dec;
-                    self.bump();
-                }
-                _ => break,
-            }
-        }
-
-        Ok(res)
-    }
-
-    fn parse_exponent(&mut self, mut res: f64) -> Result<f64, ParserError> {
-        self.bump();
-
-        let mut exp = 0;
-        let mut neg_exp = false;
-
-        if self.ch_is('+') {
-            self.bump();
-        } else if self.ch_is('-') {
-            self.bump();
-            neg_exp = true;
-        }
-
-        // Make sure a digit follows the exponent place.
-        match self.ch_or_null() {
-            '0'..='9' => (),
-            _ => return self.error(InvalidNumber),
-        }
-        while !self.eof() {
-            match self.ch_or_null() {
-                c @ '0'..='9' => {
-                    exp *= 10;
-                    exp += (c as usize) - ('0' as usize);
-
-                    self.bump();
-                }
-                _ => break,
-            }
-        }
-
-        let exp = 10_f64.powi(exp as i32);
-        if neg_exp {
-            res /= exp;
-        } else {
-            res *= exp;
-        }
-
-        Ok(res)
-    }
-
-    fn decode_hex_escape(&mut self) -> Result<u16, ParserError> {
-        let mut i = 0;
-        let mut n = 0;
-        while i < 4 && !self.eof() {
-            self.bump();
-            n = match self.ch_or_null() {
-                c @ '0'..='9' => n * 16 + ((c as u16) - ('0' as u16)),
-                'a' | 'A' => n * 16 + 10,
-                'b' | 'B' => n * 16 + 11,
-                'c' | 'C' => n * 16 + 12,
-                'd' | 'D' => n * 16 + 13,
-                'e' | 'E' => n * 16 + 14,
-                'f' | 'F' => n * 16 + 15,
-                _ => return self.error(InvalidEscape),
-            };
-
-            i += 1;
-        }
-
-        // Error out if we didn't parse 4 digits.
-        if i != 4 {
-            return self.error(InvalidEscape);
-        }
-
-        Ok(n)
-    }
-
-    fn parse_str(&mut self) -> Result<string::String, ParserError> {
-        let mut escape = false;
-        let mut res = string::String::new();
-
-        loop {
-            self.bump();
-            if self.eof() {
-                return self.error(EOFWhileParsingString);
-            }
-
-            if escape {
-                match self.ch_or_null() {
-                    '"' => res.push('"'),
-                    '\\' => res.push('\\'),
-                    '/' => res.push('/'),
-                    'b' => res.push('\x08'),
-                    'f' => res.push('\x0c'),
-                    'n' => res.push('\n'),
-                    'r' => res.push('\r'),
-                    't' => res.push('\t'),
-                    'u' => match self.decode_hex_escape()? {
-                        0xDC00..=0xDFFF => return self.error(LoneLeadingSurrogateInHexEscape),
-
-                        // Non-BMP characters are encoded as a sequence of
-                        // two hex escapes, representing UTF-16 surrogates.
-                        n1 @ 0xD800..=0xDBFF => {
-                            match (self.next_char(), self.next_char()) {
-                                (Some('\\'), Some('u')) => (),
-                                _ => return self.error(UnexpectedEndOfHexEscape),
-                            }
-
-                            let n2 = self.decode_hex_escape()?;
-                            if !(0xDC00..=0xDFFF).contains(&n2) {
-                                return self.error(LoneLeadingSurrogateInHexEscape);
-                            }
-                            let c =
-                                (u32::from(n1 - 0xD800) << 10 | u32::from(n2 - 0xDC00)) + 0x1_0000;
-                            res.push(char::from_u32(c).unwrap());
-                        }
-
-                        n => match char::from_u32(u32::from(n)) {
-                            Some(c) => res.push(c),
-                            None => return self.error(InvalidUnicodeCodePoint),
-                        },
-                    },
-                    _ => return self.error(InvalidEscape),
-                }
-                escape = false;
-            } else if self.ch_is('\\') {
-                escape = true;
-            } else {
-                match self.ch {
-                    Some('"') => {
-                        self.bump();
-                        return Ok(res);
-                    }
-                    Some(c) => res.push(c),
-                    None => unreachable!(),
-                }
-            }
-        }
-    }
-
-    // Invoked at each iteration, consumes the stream until it has enough
-    // information to return a JsonEvent.
-    // Manages an internal state so that parsing can be interrupted and resumed.
-    // Also keeps track of the position in the logical structure of the json
-    // stream isize the form of a stack that can be queried by the user using the
-    // stack() method.
-    fn parse(&mut self) -> JsonEvent {
-        loop {
-            // The only paths where the loop can spin a new iteration
-            // are in the cases ParseArrayComma and ParseObjectComma if ','
-            // is parsed. In these cases the state is set to (respectively)
-            // ParseArray(false) and ParseObject(false), which always return,
-            // so there is no risk of getting stuck in an infinite loop.
-            // All other paths return before the end of the loop's iteration.
-            self.parse_whitespace();
-
-            match self.state {
-                ParseStart => {
-                    return self.parse_start();
-                }
-                ParseArray(first) => {
-                    return self.parse_array(first);
-                }
-                ParseArrayComma => {
-                    if let Some(evt) = self.parse_array_comma_or_end() {
-                        return evt;
-                    }
-                }
-                ParseObject(first) => {
-                    return self.parse_object(first);
-                }
-                ParseObjectComma => {
-                    self.stack.pop();
-                    if self.ch_is(',') {
-                        self.state = ParseObject(false);
-                        self.bump();
-                    } else {
-                        return self.parse_object_end();
-                    }
-                }
-                _ => {
-                    return self.error_event(InvalidSyntax);
-                }
-            }
-        }
-    }
-
-    fn parse_start(&mut self) -> JsonEvent {
-        let val = self.parse_value();
-        self.state = match val {
-            Error(_) => ParseFinished,
-            ArrayStart => ParseArray(true),
-            ObjectStart => ParseObject(true),
-            _ => ParseBeforeFinish,
-        };
-        val
-    }
-
-    fn parse_array(&mut self, first: bool) -> JsonEvent {
-        if self.ch_is(']') {
-            if !first {
-                self.error_event(InvalidSyntax)
-            } else {
-                self.state = if self.stack.is_empty() {
-                    ParseBeforeFinish
-                } else if self.stack.last_is_index() {
-                    ParseArrayComma
-                } else {
-                    ParseObjectComma
-                };
-                self.bump();
-                ArrayEnd
-            }
-        } else {
-            if first {
-                self.stack.push_index(0);
-            }
-            let val = self.parse_value();
-            self.state = match val {
-                Error(_) => ParseFinished,
-                ArrayStart => ParseArray(true),
-                ObjectStart => ParseObject(true),
-                _ => ParseArrayComma,
-            };
-            val
-        }
-    }
-
-    fn parse_array_comma_or_end(&mut self) -> Option<JsonEvent> {
-        if self.ch_is(',') {
-            self.stack.bump_index();
-            self.state = ParseArray(false);
-            self.bump();
-            None
-        } else if self.ch_is(']') {
-            self.stack.pop();
-            self.state = if self.stack.is_empty() {
-                ParseBeforeFinish
-            } else if self.stack.last_is_index() {
-                ParseArrayComma
-            } else {
-                ParseObjectComma
-            };
-            self.bump();
-            Some(ArrayEnd)
-        } else if self.eof() {
-            Some(self.error_event(EOFWhileParsingArray))
-        } else {
-            Some(self.error_event(InvalidSyntax))
-        }
-    }
-
-    fn parse_object(&mut self, first: bool) -> JsonEvent {
-        if self.ch_is('}') {
-            if !first {
-                if self.stack.is_empty() {
-                    return self.error_event(TrailingComma);
-                } else {
-                    self.stack.pop();
-                }
-            }
-            self.state = if self.stack.is_empty() {
-                ParseBeforeFinish
-            } else if self.stack.last_is_index() {
-                ParseArrayComma
-            } else {
-                ParseObjectComma
-            };
-            self.bump();
-            return ObjectEnd;
-        }
-        if self.eof() {
-            return self.error_event(EOFWhileParsingObject);
-        }
-        if !self.ch_is('"') {
-            return self.error_event(KeyMustBeAString);
-        }
-        let s = match self.parse_str() {
-            Ok(s) => s,
-            Err(e) => {
-                self.state = ParseFinished;
-                return Error(e);
-            }
-        };
-        self.parse_whitespace();
-        if self.eof() {
-            return self.error_event(EOFWhileParsingObject);
-        } else if self.ch_or_null() != ':' {
-            return self.error_event(ExpectedColon);
-        }
-        self.stack.push_key(s);
-        self.bump();
-        self.parse_whitespace();
-
-        let val = self.parse_value();
-
-        self.state = match val {
-            Error(_) => ParseFinished,
-            ArrayStart => ParseArray(true),
-            ObjectStart => ParseObject(true),
-            _ => ParseObjectComma,
-        };
-        val
-    }
-
-    fn parse_object_end(&mut self) -> JsonEvent {
-        if self.ch_is('}') {
-            self.state = if self.stack.is_empty() {
-                ParseBeforeFinish
-            } else if self.stack.last_is_index() {
-                ParseArrayComma
-            } else {
-                ParseObjectComma
-            };
-            self.bump();
-            ObjectEnd
-        } else if self.eof() {
-            self.error_event(EOFWhileParsingObject)
-        } else {
-            self.error_event(InvalidSyntax)
-        }
-    }
-
-    fn parse_value(&mut self) -> JsonEvent {
-        if self.eof() {
-            return self.error_event(EOFWhileParsingValue);
-        }
-        match self.ch_or_null() {
-            'n' => self.parse_ident("ull", NullValue),
-            't' => self.parse_ident("rue", BooleanValue(true)),
-            'f' => self.parse_ident("alse", BooleanValue(false)),
-            '0'..='9' | '-' => self.parse_number(),
-            '"' => match self.parse_str() {
-                Ok(s) => StringValue(s),
-                Err(e) => Error(e),
-            },
-            '[' => {
-                self.bump();
-                ArrayStart
-            }
-            '{' => {
-                self.bump();
-                ObjectStart
-            }
-            _ => self.error_event(InvalidSyntax),
-        }
-    }
-
-    fn parse_ident(&mut self, ident: &str, value: JsonEvent) -> JsonEvent {
-        if ident.chars().all(|c| Some(c) == self.next_char()) {
-            self.bump();
-            value
-        } else {
-            Error(SyntaxError(InvalidSyntax, self.line, self.col))
-        }
-    }
-
-    fn error_event(&mut self, reason: ErrorCode) -> JsonEvent {
-        self.state = ParseFinished;
-        Error(SyntaxError(reason, self.line, self.col))
-    }
-}
-
-/// A Builder consumes a json::Parser to create a generic Json structure.
-pub struct Builder<T> {
-    parser: Parser<T>,
-    token: Option<JsonEvent>,
-}
-
-impl<T: Iterator<Item = char>> Builder<T> {
-    /// Creates a JSON Builder.
-    pub fn new(src: T) -> Builder<T> {
-        Builder { parser: Parser::new(src), token: None }
-    }
-
-    // Decode a Json value from a Parser.
-    pub fn build(&mut self) -> Result<Json, BuilderError> {
-        self.bump();
-        let result = self.build_value();
-        self.bump();
-        match self.token {
-            None => {}
-            Some(Error(ref e)) => {
-                return Err(e.clone());
-            }
-            ref tok => {
-                panic!("unexpected token {:?}", tok.clone());
-            }
-        }
-        result
-    }
-
-    fn bump(&mut self) {
-        self.token = self.parser.next();
-    }
-
-    fn build_value(&mut self) -> Result<Json, BuilderError> {
-        match self.token {
-            Some(NullValue) => Ok(Json::Null),
-            Some(I64Value(n)) => Ok(Json::I64(n)),
-            Some(U64Value(n)) => Ok(Json::U64(n)),
-            Some(F64Value(n)) => Ok(Json::F64(n)),
-            Some(BooleanValue(b)) => Ok(Json::Boolean(b)),
-            Some(StringValue(ref mut s)) => {
-                let mut temp = string::String::new();
-                swap(s, &mut temp);
-                Ok(Json::String(temp))
-            }
-            Some(Error(ref e)) => Err(e.clone()),
-            Some(ArrayStart) => self.build_array(),
-            Some(ObjectStart) => self.build_object(),
-            Some(ObjectEnd) => self.parser.error(InvalidSyntax),
-            Some(ArrayEnd) => self.parser.error(InvalidSyntax),
-            None => self.parser.error(EOFWhileParsingValue),
-        }
-    }
-
-    fn build_array(&mut self) -> Result<Json, BuilderError> {
-        self.bump();
-        let mut values = Vec::new();
-
-        loop {
-            if self.token == Some(ArrayEnd) {
-                return Ok(Json::Array(values.into_iter().collect()));
-            }
-            match self.build_value() {
-                Ok(v) => values.push(v),
-                Err(e) => return Err(e),
-            }
-            self.bump();
-        }
-    }
-
-    fn build_object(&mut self) -> Result<Json, BuilderError> {
-        self.bump();
-
-        let mut values = BTreeMap::new();
-
-        loop {
-            match self.token {
-                Some(ObjectEnd) => {
-                    return Ok(Json::Object(values));
-                }
-                Some(Error(ref e)) => {
-                    return Err(e.clone());
-                }
-                None => {
-                    break;
-                }
-                _ => {}
-            }
-            let key = match self.parser.stack().top() {
-                Some(StackElement::Key(k)) => k.to_owned(),
-                _ => {
-                    panic!("invalid state");
-                }
-            };
-            match self.build_value() {
-                Ok(value) => {
-                    values.insert(key, value);
-                }
-                Err(e) => {
-                    return Err(e);
-                }
-            }
-            self.bump();
-        }
-        self.parser.error(EOFWhileParsingObject)
-    }
-}
-
-/// Decodes a json value from a string
-pub fn from_str(s: &str) -> Result<Json, BuilderError> {
-    let mut builder = Builder::new(s.chars());
-    builder.build()
-}
-
-/// A trait for converting values to JSON
-pub trait ToJson {
-    /// Converts the value of `self` to an instance of JSON
-    fn to_json(&self) -> Json;
-}
-
-macro_rules! to_json_impl_i64 {
-    ($($t:ty), +) => (
-        $(impl ToJson for $t {
-            fn to_json(&self) -> Json {
-                Json::I64(*self as i64)
-            }
-        })+
-    )
-}
-
-to_json_impl_i64! { isize, i8, i16, i32, i64 }
-
-macro_rules! to_json_impl_u64 {
-    ($($t:ty), +) => (
-        $(impl ToJson for $t {
-            fn to_json(&self) -> Json {
-                Json::U64(*self as u64)
-            }
-        })+
-    )
-}
-
-to_json_impl_u64! { usize, u8, u16, u32, u64 }
-
-impl ToJson for Json {
-    fn to_json(&self) -> Json {
-        self.clone()
-    }
-}
-
-impl ToJson for f32 {
-    fn to_json(&self) -> Json {
-        f64::from(*self).to_json()
-    }
-}
-
-impl ToJson for f64 {
-    fn to_json(&self) -> Json {
-        match self.classify() {
-            Fp::Nan | Fp::Infinite => Json::Null,
-            _ => Json::F64(*self),
-        }
-    }
-}
-
-impl ToJson for () {
-    fn to_json(&self) -> Json {
-        Json::Null
-    }
-}
-
-impl ToJson for bool {
-    fn to_json(&self) -> Json {
-        Json::Boolean(*self)
-    }
-}
-
-impl ToJson for str {
-    fn to_json(&self) -> Json {
-        Json::String(self.to_string())
-    }
-}
-
-impl ToJson for string::String {
-    fn to_json(&self) -> Json {
-        Json::String((*self).clone())
-    }
-}
-
-impl<'a> ToJson for Cow<'a, str> {
-    fn to_json(&self) -> Json {
-        Json::String(self.to_string())
-    }
-}
-
-macro_rules! tuple_impl {
-    // use variables to indicate the arity of the tuple
-    ($($tyvar:ident),* ) => {
-        // the trailing commas are for the 1 tuple
-        impl<
-            $( $tyvar : ToJson ),*
-            > ToJson for ( $( $tyvar ),* , ) {
-
-            #[inline]
-            #[allow(non_snake_case)]
-            fn to_json(&self) -> Json {
-                match *self {
-                    ($(ref $tyvar),*,) => Json::Array(vec![$($tyvar.to_json()),*])
-                }
-            }
-        }
-    }
-}
-
-tuple_impl! {A}
-tuple_impl! {A, B}
-tuple_impl! {A, B, C}
-tuple_impl! {A, B, C, D}
-tuple_impl! {A, B, C, D, E}
-tuple_impl! {A, B, C, D, E, F}
-tuple_impl! {A, B, C, D, E, F, G}
-tuple_impl! {A, B, C, D, E, F, G, H}
-tuple_impl! {A, B, C, D, E, F, G, H, I}
-tuple_impl! {A, B, C, D, E, F, G, H, I, J}
-tuple_impl! {A, B, C, D, E, F, G, H, I, J, K}
-tuple_impl! {A, B, C, D, E, F, G, H, I, J, K, L}
-
-impl<A: ToJson> ToJson for [A] {
-    fn to_json(&self) -> Json {
-        Json::Array(self.iter().map(|elt| elt.to_json()).collect())
-    }
-}
-
-impl<A: ToJson> ToJson for Vec<A> {
-    fn to_json(&self) -> Json {
-        Json::Array(self.iter().map(|elt| elt.to_json()).collect())
-    }
-}
-
-impl<'a, A: ToJson> ToJson for Cow<'a, [A]>
-where
-    [A]: ToOwned,
-{
-    fn to_json(&self) -> Json {
-        Json::Array(self.iter().map(|elt| elt.to_json()).collect())
-    }
-}
-
-impl<T: ToString, A: ToJson> ToJson for BTreeMap<T, A> {
-    fn to_json(&self) -> Json {
-        let mut d = BTreeMap::new();
-        for (key, value) in self {
-            d.insert(key.to_string(), value.to_json());
-        }
-        Json::Object(d)
-    }
-}
-
-impl<A: ToJson> ToJson for HashMap<string::String, A> {
-    fn to_json(&self) -> Json {
-        let mut d = BTreeMap::new();
-        for (key, value) in self {
-            d.insert((*key).clone(), value.to_json());
-        }
-        Json::Object(d)
-    }
-}
-
-impl<A: ToJson> ToJson for Option<A> {
-    fn to_json(&self) -> Json {
-        match *self {
-            None => Json::Null,
-            Some(ref value) => value.to_json(),
-        }
-    }
-}
-
-struct FormatShim<'a, 'b> {
-    inner: &'a mut fmt::Formatter<'b>,
-}
-
-impl<'a, 'b> fmt::Write for FormatShim<'a, 'b> {
-    fn write_str(&mut self, s: &str) -> fmt::Result {
-        match self.inner.write_str(s) {
-            Ok(_) => Ok(()),
-            Err(_) => Err(fmt::Error),
-        }
-    }
-}
-
-impl fmt::Display for Json {
-    /// Encodes a json value into a string
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        let mut shim = FormatShim { inner: f };
-        let mut encoder = Encoder::new(&mut shim);
-        match self.encode(&mut encoder) {
-            Ok(_) => Ok(()),
-            Err(_) => Err(fmt::Error),
-        }
-    }
-}
-
-impl<'a> fmt::Display for PrettyJson<'a> {
-    /// Encodes a json value into a string
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        let mut shim = FormatShim { inner: f };
-        let mut encoder = PrettyEncoder::new(&mut shim);
-        match self.inner.encode(&mut encoder) {
-            Ok(_) => Ok(()),
-            Err(_) => Err(fmt::Error),
-        }
-    }
-}
-
-impl<'a, T: for<'r> Encodable<Encoder<'r>>> fmt::Display for AsJson<'a, T> {
-    /// Encodes a json value into a string
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        let mut shim = FormatShim { inner: f };
-        let mut encoder = Encoder::new(&mut shim);
-        match self.inner.encode(&mut encoder) {
-            Ok(_) => Ok(()),
-            Err(_) => Err(fmt::Error),
-        }
-    }
-}
-
-impl<'a, T> AsPrettyJson<'a, T> {
-    /// Sets the indentation level for the emitted JSON
-    pub fn indent(mut self, indent: usize) -> AsPrettyJson<'a, T> {
-        self.indent = Some(indent);
-        self
-    }
-}
-
-impl<'a, T: for<'x> Encodable<PrettyEncoder<'x>>> fmt::Display for AsPrettyJson<'a, T> {
-    /// Encodes a json value into a string
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        let mut shim = FormatShim { inner: f };
-        let mut encoder = PrettyEncoder::new(&mut shim);
-        if let Some(n) = self.indent {
-            encoder.set_indent(n);
-        }
-        match self.inner.encode(&mut encoder) {
-            Ok(_) => Ok(()),
-            Err(_) => Err(fmt::Error),
-        }
-    }
-}
-
-impl FromStr for Json {
-    type Err = BuilderError;
-    fn from_str(s: &str) -> Result<Json, BuilderError> {
-        from_str(s)
-    }
-}
-
-#[cfg(test)]
-mod tests;
diff --git a/compiler/rustc_serialize/src/json/tests.rs b/compiler/rustc_serialize/src/json/tests.rs
deleted file mode 100644
index 01678fb..0000000
--- a/compiler/rustc_serialize/src/json/tests.rs
+++ /dev/null
@@ -1,147 +0,0 @@
-// Benchmarks and tests that require private items
-
-extern crate test;
-use super::{from_str, Parser, Stack, StackElement};
-use std::string;
-use test::Bencher;
-
-#[test]
-fn test_stack() {
-    let mut stack = Stack::new();
-
-    assert!(stack.is_empty());
-    assert!(stack.is_empty());
-    assert!(!stack.last_is_index());
-
-    stack.push_index(0);
-    stack.bump_index();
-
-    assert!(stack.len() == 1);
-    assert!(stack.is_equal_to(&[StackElement::Index(1)]));
-    assert!(stack.starts_with(&[StackElement::Index(1)]));
-    assert!(stack.ends_with(&[StackElement::Index(1)]));
-    assert!(stack.last_is_index());
-    assert!(stack.get(0) == StackElement::Index(1));
-
-    stack.push_key("foo".to_string());
-
-    assert!(stack.len() == 2);
-    assert!(stack.is_equal_to(&[StackElement::Index(1), StackElement::Key("foo")]));
-    assert!(stack.starts_with(&[StackElement::Index(1), StackElement::Key("foo")]));
-    assert!(stack.starts_with(&[StackElement::Index(1)]));
-    assert!(stack.ends_with(&[StackElement::Index(1), StackElement::Key("foo")]));
-    assert!(stack.ends_with(&[StackElement::Key("foo")]));
-    assert!(!stack.last_is_index());
-    assert!(stack.get(0) == StackElement::Index(1));
-    assert!(stack.get(1) == StackElement::Key("foo"));
-
-    stack.push_key("bar".to_string());
-
-    assert!(stack.len() == 3);
-    assert!(stack.is_equal_to(&[
-        StackElement::Index(1),
-        StackElement::Key("foo"),
-        StackElement::Key("bar")
-    ]));
-    assert!(stack.starts_with(&[StackElement::Index(1)]));
-    assert!(stack.starts_with(&[StackElement::Index(1), StackElement::Key("foo")]));
-    assert!(stack.starts_with(&[
-        StackElement::Index(1),
-        StackElement::Key("foo"),
-        StackElement::Key("bar")
-    ]));
-    assert!(stack.ends_with(&[StackElement::Key("bar")]));
-    assert!(stack.ends_with(&[StackElement::Key("foo"), StackElement::Key("bar")]));
-    assert!(stack.ends_with(&[
-        StackElement::Index(1),
-        StackElement::Key("foo"),
-        StackElement::Key("bar")
-    ]));
-    assert!(!stack.last_is_index());
-    assert!(stack.get(0) == StackElement::Index(1));
-    assert!(stack.get(1) == StackElement::Key("foo"));
-    assert!(stack.get(2) == StackElement::Key("bar"));
-
-    stack.pop();
-
-    assert!(stack.len() == 2);
-    assert!(stack.is_equal_to(&[StackElement::Index(1), StackElement::Key("foo")]));
-    assert!(stack.starts_with(&[StackElement::Index(1), StackElement::Key("foo")]));
-    assert!(stack.starts_with(&[StackElement::Index(1)]));
-    assert!(stack.ends_with(&[StackElement::Index(1), StackElement::Key("foo")]));
-    assert!(stack.ends_with(&[StackElement::Key("foo")]));
-    assert!(!stack.last_is_index());
-    assert!(stack.get(0) == StackElement::Index(1));
-    assert!(stack.get(1) == StackElement::Key("foo"));
-}
-
-#[bench]
-fn bench_streaming_small(b: &mut Bencher) {
-    b.iter(|| {
-        let mut parser = Parser::new(
-            r#"{
-                "a": 1.0,
-                "b": [
-                    true,
-                    "foo\nbar",
-                    { "c": {"d": null} }
-                ]
-            }"#
-            .chars(),
-        );
-        loop {
-            match parser.next() {
-                None => return,
-                _ => {}
-            }
-        }
-    });
-}
-#[bench]
-fn bench_small(b: &mut Bencher) {
-    b.iter(|| {
-        let _ = from_str(
-            r#"{
-            "a": 1.0,
-            "b": [
-                true,
-                "foo\nbar",
-                { "c": {"d": null} }
-            ]
-        }"#,
-        );
-    });
-}
-
-fn big_json() -> string::String {
-    let mut src = "[\n".to_string();
-    for _ in 0..500 {
-        src.push_str(
-            r#"{ "a": true, "b": null, "c":3.1415, "d": "Hello world", "e": \
-                        [1,2,3]},"#,
-        );
-    }
-    src.push_str("{}]");
-    return src;
-}
-
-#[bench]
-fn bench_streaming_large(b: &mut Bencher) {
-    let src = big_json();
-    b.iter(|| {
-        let mut parser = Parser::new(src.chars());
-        loop {
-            match parser.next() {
-                None => return,
-                _ => {}
-            }
-        }
-    });
-}
-#[bench]
-fn bench_large(b: &mut Bencher) {
-    let src = big_json();
-    b.iter(|| {
-        let _ = from_str(&src);
-    });
-}
diff --git a/compiler/rustc_serialize/src/lib.rs b/compiler/rustc_serialize/src/lib.rs
index bd257dc..e606f42 100644
--- a/compiler/rustc_serialize/src/lib.rs
+++ b/compiler/rustc_serialize/src/lib.rs
@@ -10,7 +10,6 @@
     test(attr(allow(unused_variables), deny(warnings)))
 )]
 #![feature(never_type)]
-#![feature(nll)]
 #![feature(associated_type_bounds)]
 #![feature(min_specialization)]
 #![feature(core_intrinsics)]
@@ -25,7 +24,5 @@
 mod collection_impls;
 mod serialize;
 
-pub mod json;
-
 pub mod leb128;
 pub mod opaque;
diff --git a/compiler/rustc_serialize/src/opaque.rs b/compiler/rustc_serialize/src/opaque.rs
index 5e5cbac..366efe9 100644
--- a/compiler/rustc_serialize/src/opaque.rs
+++ b/compiler/rustc_serialize/src/opaque.rs
@@ -1,5 +1,5 @@
 use crate::leb128::{self, max_leb128_len};
-use crate::serialize::{self, Decoder as _, Encoder as _};
+use crate::serialize::{Decodable, Decoder, Encodable, Encoder};
 use std::convert::TryInto;
 use std::fs::File;
 use std::io::{self, Write};
@@ -11,25 +11,23 @@
 // Encoder
 // -----------------------------------------------------------------------------
 
-pub type EncodeResult = Result<(), !>;
-
-pub struct Encoder {
+pub struct MemEncoder {
     pub data: Vec<u8>,
 }
 
-impl Encoder {
-    pub fn new(data: Vec<u8>) -> Encoder {
-        Encoder { data }
-    }
-
-    pub fn into_inner(self) -> Vec<u8> {
-        self.data
+impl MemEncoder {
+    pub fn new() -> MemEncoder {
+        MemEncoder { data: vec![] }
     }
 
     #[inline]
     pub fn position(&self) -> usize {
         self.data.len()
     }
+
+    pub fn finish(self) -> Vec<u8> {
+        self.data
+    }
 }
 
 macro_rules! write_leb128 {
@@ -49,8 +47,6 @@
             let encoded = leb128::$fun(buf, $value);
             $enc.data.set_len(old_len + encoded.len());
         }
-
-        Ok(())
     }};
 }
 
@@ -61,119 +57,108 @@
 /// [utf8]: https://en.wikipedia.org/w/index.php?title=UTF-8&oldid=1058865525#Codepage_layout
 const STR_SENTINEL: u8 = 0xC1;
 
-impl serialize::Encoder for Encoder {
-    type Error = !;
-
+impl Encoder for MemEncoder {
     #[inline]
-    fn emit_unit(&mut self) -> EncodeResult {
-        Ok(())
-    }
-
-    #[inline]
-    fn emit_usize(&mut self, v: usize) -> EncodeResult {
+    fn emit_usize(&mut self, v: usize) {
         write_leb128!(self, v, usize, write_usize_leb128)
     }
 
     #[inline]
-    fn emit_u128(&mut self, v: u128) -> EncodeResult {
-        write_leb128!(self, v, u128, write_u128_leb128)
+    fn emit_u128(&mut self, v: u128) {
+        write_leb128!(self, v, u128, write_u128_leb128);
     }
 
     #[inline]
-    fn emit_u64(&mut self, v: u64) -> EncodeResult {
-        write_leb128!(self, v, u64, write_u64_leb128)
+    fn emit_u64(&mut self, v: u64) {
+        write_leb128!(self, v, u64, write_u64_leb128);
     }
 
     #[inline]
-    fn emit_u32(&mut self, v: u32) -> EncodeResult {
-        write_leb128!(self, v, u32, write_u32_leb128)
+    fn emit_u32(&mut self, v: u32) {
+        write_leb128!(self, v, u32, write_u32_leb128);
     }
 
     #[inline]
-    fn emit_u16(&mut self, v: u16) -> EncodeResult {
+    fn emit_u16(&mut self, v: u16) {
         self.data.extend_from_slice(&v.to_le_bytes());
-        Ok(())
     }
 
     #[inline]
-    fn emit_u8(&mut self, v: u8) -> EncodeResult {
+    fn emit_u8(&mut self, v: u8) {
         self.data.push(v);
-        Ok(())
     }
 
     #[inline]
-    fn emit_isize(&mut self, v: isize) -> EncodeResult {
+    fn emit_isize(&mut self, v: isize) {
         write_leb128!(self, v, isize, write_isize_leb128)
     }
 
     #[inline]
-    fn emit_i128(&mut self, v: i128) -> EncodeResult {
+    fn emit_i128(&mut self, v: i128) {
         write_leb128!(self, v, i128, write_i128_leb128)
     }
 
     #[inline]
-    fn emit_i64(&mut self, v: i64) -> EncodeResult {
+    fn emit_i64(&mut self, v: i64) {
         write_leb128!(self, v, i64, write_i64_leb128)
     }
 
     #[inline]
-    fn emit_i32(&mut self, v: i32) -> EncodeResult {
+    fn emit_i32(&mut self, v: i32) {
         write_leb128!(self, v, i32, write_i32_leb128)
     }
 
     #[inline]
-    fn emit_i16(&mut self, v: i16) -> EncodeResult {
+    fn emit_i16(&mut self, v: i16) {
         self.data.extend_from_slice(&v.to_le_bytes());
-        Ok(())
     }
 
     #[inline]
-    fn emit_i8(&mut self, v: i8) -> EncodeResult {
-        self.emit_u8(v as u8)
+    fn emit_i8(&mut self, v: i8) {
+        self.emit_u8(v as u8);
     }
 
     #[inline]
-    fn emit_bool(&mut self, v: bool) -> EncodeResult {
-        self.emit_u8(if v { 1 } else { 0 })
+    fn emit_bool(&mut self, v: bool) {
+        self.emit_u8(if v { 1 } else { 0 });
     }
 
     #[inline]
-    fn emit_f64(&mut self, v: f64) -> EncodeResult {
+    fn emit_f64(&mut self, v: f64) {
         let as_u64: u64 = v.to_bits();
-        self.emit_u64(as_u64)
+        self.emit_u64(as_u64);
     }
 
     #[inline]
-    fn emit_f32(&mut self, v: f32) -> EncodeResult {
+    fn emit_f32(&mut self, v: f32) {
         let as_u32: u32 = v.to_bits();
-        self.emit_u32(as_u32)
+        self.emit_u32(as_u32);
     }
 
     #[inline]
-    fn emit_char(&mut self, v: char) -> EncodeResult {
-        self.emit_u32(v as u32)
+    fn emit_char(&mut self, v: char) {
+        self.emit_u32(v as u32);
     }
 
     #[inline]
-    fn emit_str(&mut self, v: &str) -> EncodeResult {
-        self.emit_usize(v.len())?;
-        self.emit_raw_bytes(v.as_bytes())?;
-        self.emit_u8(STR_SENTINEL)
+    fn emit_str(&mut self, v: &str) {
+        self.emit_usize(v.len());
+        self.emit_raw_bytes(v.as_bytes());
+        self.emit_u8(STR_SENTINEL);
     }
 
     #[inline]
-    fn emit_raw_bytes(&mut self, s: &[u8]) -> EncodeResult {
+    fn emit_raw_bytes(&mut self, s: &[u8]) {
         self.data.extend_from_slice(s);
-        Ok(())
     }
 }
 
-pub type FileEncodeResult = Result<(), io::Error>;
+pub type FileEncodeResult = Result<usize, io::Error>;
 
 // `FileEncoder` encodes data to file via fixed-size buffer.
 //
 // When encoding large amounts of data to a file, using `FileEncoder` may be
-// preferred over using `Encoder` to encode to a `Vec`, and then writing the
+// preferred over using `MemEncoder` to encode to a `Vec`, and then writing the
 // `Vec` to file, as the latter uses as much memory as there is encoded data,
 // while the former uses the fixed amount of memory allocated to the buffer.
 // `FileEncoder` also has the advantage of not needing to reallocate as data
@@ -187,6 +172,9 @@
     buffered: usize,
     flushed: usize,
     file: File,
+    // This is used to implement delayed error handling, as described in the
+    // comment on `trait Encoder`.
+    res: Result<(), io::Error>,
 }
 
 impl FileEncoder {
@@ -207,7 +195,13 @@
 
         let file = File::create(path)?;
 
-        Ok(FileEncoder { buf: Box::new_uninit_slice(capacity), buffered: 0, flushed: 0, file })
+        Ok(FileEncoder {
+            buf: Box::new_uninit_slice(capacity),
+            buffered: 0,
+            flushed: 0,
+            file,
+            res: Ok(()),
+        })
     }
 
     #[inline]
@@ -217,7 +211,7 @@
         self.flushed + self.buffered
     }
 
-    pub fn flush(&mut self) -> FileEncodeResult {
+    pub fn flush(&mut self) {
         // This is basically a copy of `BufWriter::flush`. If `BufWriter` ever
         // offers a raw buffer access API, we can use it, and remove this.
 
@@ -272,6 +266,12 @@
             }
         }
 
+        // If we've already had an error, do nothing. It'll get reported after
+        // `finish` is called.
+        if self.res.is_err() {
+            return;
+        }
+
         let mut guard = BufGuard::new(
             unsafe { MaybeUninit::slice_assume_init_mut(&mut self.buf[..self.buffered]) },
             &mut self.buffered,
@@ -281,18 +281,20 @@
         while !guard.done() {
             match self.file.write(guard.remaining()) {
                 Ok(0) => {
-                    return Err(io::Error::new(
+                    self.res = Err(io::Error::new(
                         io::ErrorKind::WriteZero,
                         "failed to write the buffered data",
                     ));
+                    return;
                 }
                 Ok(n) => guard.consume(n),
                 Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
-                Err(e) => return Err(e),
+                Err(e) => {
+                    self.res = Err(e);
+                    return;
+                }
             }
         }
-
-        Ok(())
     }
 
     #[inline]
@@ -301,14 +303,14 @@
     }
 
     #[inline]
-    fn write_one(&mut self, value: u8) -> FileEncodeResult {
+    fn write_one(&mut self, value: u8) {
         // We ensure this during `FileEncoder` construction.
         debug_assert!(self.capacity() >= 1);
 
         let mut buffered = self.buffered;
 
         if std::intrinsics::unlikely(buffered >= self.capacity()) {
-            self.flush()?;
+            self.flush();
             buffered = 0;
         }
 
@@ -319,12 +321,10 @@
         }
 
         self.buffered = buffered + 1;
-
-        Ok(())
     }
 
     #[inline]
-    fn write_all(&mut self, buf: &[u8]) -> FileEncodeResult {
+    fn write_all(&mut self, buf: &[u8]) {
         let capacity = self.capacity();
         let buf_len = buf.len();
 
@@ -332,7 +332,7 @@
             let mut buffered = self.buffered;
 
             if std::intrinsics::unlikely(buf_len > capacity - buffered) {
-                self.flush()?;
+                self.flush();
                 buffered = 0;
             }
 
@@ -345,16 +345,20 @@
             }
 
             self.buffered = buffered + buf_len;
-
-            Ok(())
         } else {
-            self.write_all_unbuffered(buf)
+            self.write_all_unbuffered(buf);
         }
     }
 
-    fn write_all_unbuffered(&mut self, mut buf: &[u8]) -> FileEncodeResult {
+    fn write_all_unbuffered(&mut self, mut buf: &[u8]) {
+        // If we've already had an error, do nothing. It'll get reported after
+        // `finish` is called.
+        if self.res.is_err() {
+            return;
+        }
+
         if self.buffered > 0 {
-            self.flush()?;
+            self.flush();
         }
 
         // This is basically a copy of `Write::write_all` but also updates our
@@ -364,26 +368,37 @@
         while !buf.is_empty() {
             match self.file.write(buf) {
                 Ok(0) => {
-                    return Err(io::Error::new(
+                    self.res = Err(io::Error::new(
                         io::ErrorKind::WriteZero,
                         "failed to write whole buffer",
                     ));
+                    return;
                 }
                 Ok(n) => {
                     buf = &buf[n..];
                     self.flushed += n;
                 }
                 Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
-                Err(e) => return Err(e),
+                Err(e) => {
+                    self.res = Err(e);
+                    return;
+                }
             }
         }
+    }
 
-        Ok(())
+    pub fn finish(mut self) -> Result<usize, io::Error> {
+        self.flush();
+
+        let res = std::mem::replace(&mut self.res, Ok(()));
+        res.map(|()| self.position())
     }
 }
 
 impl Drop for FileEncoder {
     fn drop(&mut self) {
+        // Likely to be a no-op, because `finish` should have been called and
+        // it also flushes. But do it just in case.
         let _result = self.flush();
     }
 }
@@ -399,7 +414,7 @@
 
         // This can't overflow. See assertion in `FileEncoder::with_capacity`.
         if std::intrinsics::unlikely(buffered + MAX_ENCODED_LEN > $enc.capacity()) {
-            $enc.flush()?;
+            $enc.flush();
             buffered = 0;
         }
 
@@ -411,111 +426,102 @@
 
         let encoded = leb128::$fun(buf, $value);
         $enc.buffered = buffered + encoded.len();
-
-        Ok(())
     }};
 }
 
-impl serialize::Encoder for FileEncoder {
-    type Error = io::Error;
-
+impl Encoder for FileEncoder {
     #[inline]
-    fn emit_unit(&mut self) -> FileEncodeResult {
-        Ok(())
-    }
-
-    #[inline]
-    fn emit_usize(&mut self, v: usize) -> FileEncodeResult {
+    fn emit_usize(&mut self, v: usize) {
         file_encoder_write_leb128!(self, v, usize, write_usize_leb128)
     }
 
     #[inline]
-    fn emit_u128(&mut self, v: u128) -> FileEncodeResult {
+    fn emit_u128(&mut self, v: u128) {
         file_encoder_write_leb128!(self, v, u128, write_u128_leb128)
     }
 
     #[inline]
-    fn emit_u64(&mut self, v: u64) -> FileEncodeResult {
+    fn emit_u64(&mut self, v: u64) {
         file_encoder_write_leb128!(self, v, u64, write_u64_leb128)
     }
 
     #[inline]
-    fn emit_u32(&mut self, v: u32) -> FileEncodeResult {
+    fn emit_u32(&mut self, v: u32) {
         file_encoder_write_leb128!(self, v, u32, write_u32_leb128)
     }
 
     #[inline]
-    fn emit_u16(&mut self, v: u16) -> FileEncodeResult {
-        self.write_all(&v.to_le_bytes())
+    fn emit_u16(&mut self, v: u16) {
+        self.write_all(&v.to_le_bytes());
     }
 
     #[inline]
-    fn emit_u8(&mut self, v: u8) -> FileEncodeResult {
-        self.write_one(v)
+    fn emit_u8(&mut self, v: u8) {
+        self.write_one(v);
     }
 
     #[inline]
-    fn emit_isize(&mut self, v: isize) -> FileEncodeResult {
+    fn emit_isize(&mut self, v: isize) {
         file_encoder_write_leb128!(self, v, isize, write_isize_leb128)
     }
 
     #[inline]
-    fn emit_i128(&mut self, v: i128) -> FileEncodeResult {
+    fn emit_i128(&mut self, v: i128) {
         file_encoder_write_leb128!(self, v, i128, write_i128_leb128)
     }
 
     #[inline]
-    fn emit_i64(&mut self, v: i64) -> FileEncodeResult {
+    fn emit_i64(&mut self, v: i64) {
         file_encoder_write_leb128!(self, v, i64, write_i64_leb128)
     }
 
     #[inline]
-    fn emit_i32(&mut self, v: i32) -> FileEncodeResult {
+    fn emit_i32(&mut self, v: i32) {
         file_encoder_write_leb128!(self, v, i32, write_i32_leb128)
     }
 
     #[inline]
-    fn emit_i16(&mut self, v: i16) -> FileEncodeResult {
-        self.write_all(&v.to_le_bytes())
+    fn emit_i16(&mut self, v: i16) {
+        self.write_all(&v.to_le_bytes());
     }
 
     #[inline]
-    fn emit_i8(&mut self, v: i8) -> FileEncodeResult {
-        self.emit_u8(v as u8)
+    fn emit_i8(&mut self, v: i8) {
+        self.emit_u8(v as u8);
     }
 
     #[inline]
-    fn emit_bool(&mut self, v: bool) -> FileEncodeResult {
-        self.emit_u8(if v { 1 } else { 0 })
+    fn emit_bool(&mut self, v: bool) {
+        self.emit_u8(if v { 1 } else { 0 });
     }
 
     #[inline]
-    fn emit_f64(&mut self, v: f64) -> FileEncodeResult {
+    fn emit_f64(&mut self, v: f64) {
         let as_u64: u64 = v.to_bits();
-        self.emit_u64(as_u64)
+        self.emit_u64(as_u64);
     }
 
     #[inline]
-    fn emit_f32(&mut self, v: f32) -> FileEncodeResult {
+    fn emit_f32(&mut self, v: f32) {
         let as_u32: u32 = v.to_bits();
-        self.emit_u32(as_u32)
+        self.emit_u32(as_u32);
     }
 
     #[inline]
-    fn emit_char(&mut self, v: char) -> FileEncodeResult {
-        self.emit_u32(v as u32)
+    fn emit_char(&mut self, v: char) {
+        self.emit_u32(v as u32);
     }
 
     #[inline]
-    fn emit_str(&mut self, v: &str) -> FileEncodeResult {
-        self.emit_usize(v.len())?;
-        self.emit_raw_bytes(v.as_bytes())?;
-        self.emit_u8(STR_SENTINEL)
+    fn emit_str(&mut self, v: &str) {
+        self.emit_usize(v.len());
+        self.emit_raw_bytes(v.as_bytes());
+        self.emit_u8(STR_SENTINEL);
     }
 
     #[inline]
-    fn emit_raw_bytes(&mut self, s: &[u8]) -> FileEncodeResult {
-        self.write_all(s)
+    fn emit_raw_bytes(&mut self, s: &[u8]) {
+        self.write_all(s);
     }
 }
 
@@ -523,15 +529,15 @@
 // Decoder
 // -----------------------------------------------------------------------------
 
-pub struct Decoder<'a> {
+pub struct MemDecoder<'a> {
     pub data: &'a [u8],
     position: usize,
 }
 
-impl<'a> Decoder<'a> {
+impl<'a> MemDecoder<'a> {
     #[inline]
-    pub fn new(data: &'a [u8], position: usize) -> Decoder<'a> {
-        Decoder { data, position }
+    pub fn new(data: &'a [u8], position: usize) -> MemDecoder<'a> {
+        MemDecoder { data, position }
     }
 
     #[inline]
@@ -554,7 +560,7 @@
     ($dec:expr, $fun:ident) => {{ leb128::$fun($dec.data, &mut $dec.position) }};
 }
 
-impl<'a> serialize::Decoder for Decoder<'a> {
+impl<'a> Decoder for MemDecoder<'a> {
     #[inline]
     fn read_u128(&mut self) -> u128 {
         read_leb128!(self, read_u128_leb128)
@@ -676,25 +682,25 @@
 
 // Specialize encoding byte slices. This specialization also applies to encoding `Vec<u8>`s, etc.,
 // since the default implementations call `encode` on their slices internally.
-impl serialize::Encodable<Encoder> for [u8] {
-    fn encode(&self, e: &mut Encoder) -> EncodeResult {
-        serialize::Encoder::emit_usize(e, self.len())?;
-        e.emit_raw_bytes(self)
+impl Encodable<MemEncoder> for [u8] {
+    fn encode(&self, e: &mut MemEncoder) {
+        Encoder::emit_usize(e, self.len());
+        e.emit_raw_bytes(self);
     }
 }
 
-impl serialize::Encodable<FileEncoder> for [u8] {
-    fn encode(&self, e: &mut FileEncoder) -> FileEncodeResult {
-        serialize::Encoder::emit_usize(e, self.len())?;
-        e.emit_raw_bytes(self)
+impl Encodable<FileEncoder> for [u8] {
+    fn encode(&self, e: &mut FileEncoder) {
+        Encoder::emit_usize(e, self.len());
+        e.emit_raw_bytes(self);
     }
 }
 
 // Specialize decoding `Vec<u8>`. This specialization also applies to decoding `Box<[u8]>`s, etc.,
 // since the default implementations call `decode` to produce a `Vec<u8>` internally.
-impl<'a> serialize::Decodable<Decoder<'a>> for Vec<u8> {
-    fn decode(d: &mut Decoder<'a>) -> Self {
-        let len = serialize::Decoder::read_usize(d);
+impl<'a> Decodable<MemDecoder<'a>> for Vec<u8> {
+    fn decode(d: &mut MemDecoder<'a>) -> Self {
+        let len = Decoder::read_usize(d);
         d.read_raw_bytes(len).to_owned()
     }
 }
@@ -706,31 +712,29 @@
     pub const ENCODED_SIZE: usize = 8;
 }
 
-impl serialize::Encodable<Encoder> for IntEncodedWithFixedSize {
+impl Encodable<MemEncoder> for IntEncodedWithFixedSize {
     #[inline]
-    fn encode(&self, e: &mut Encoder) -> EncodeResult {
+    fn encode(&self, e: &mut MemEncoder) {
         let _start_pos = e.position();
-        e.emit_raw_bytes(&self.0.to_le_bytes())?;
+        e.emit_raw_bytes(&self.0.to_le_bytes());
         let _end_pos = e.position();
         debug_assert_eq!((_end_pos - _start_pos), IntEncodedWithFixedSize::ENCODED_SIZE);
-        Ok(())
     }
 }
 
-impl serialize::Encodable<FileEncoder> for IntEncodedWithFixedSize {
+impl Encodable<FileEncoder> for IntEncodedWithFixedSize {
     #[inline]
-    fn encode(&self, e: &mut FileEncoder) -> FileEncodeResult {
+    fn encode(&self, e: &mut FileEncoder) {
         let _start_pos = e.position();
-        e.emit_raw_bytes(&self.0.to_le_bytes())?;
+        e.emit_raw_bytes(&self.0.to_le_bytes());
         let _end_pos = e.position();
         debug_assert_eq!((_end_pos - _start_pos), IntEncodedWithFixedSize::ENCODED_SIZE);
-        Ok(())
     }
 }
 
-impl<'a> serialize::Decodable<Decoder<'a>> for IntEncodedWithFixedSize {
+impl<'a> Decodable<MemDecoder<'a>> for IntEncodedWithFixedSize {
     #[inline]
-    fn decode(decoder: &mut Decoder<'a>) -> IntEncodedWithFixedSize {
+    fn decode(decoder: &mut MemDecoder<'a>) -> IntEncodedWithFixedSize {
         let _start_pos = decoder.position();
         let bytes = decoder.read_raw_bytes(IntEncodedWithFixedSize::ENCODED_SIZE);
         let value = u64::from_le_bytes(bytes.try_into().unwrap());
diff --git a/compiler/rustc_serialize/src/serialize.rs b/compiler/rustc_serialize/src/serialize.rs
index 7d6b8c7..36585b8 100644
--- a/compiler/rustc_serialize/src/serialize.rs
+++ b/compiler/rustc_serialize/src/serialize.rs
@@ -11,51 +11,44 @@
 use std::rc::Rc;
 use std::sync::Arc;
 
+/// A note about error handling.
+///
+/// Encoders may be fallible, but in practice failure is rare and there are so
+/// many nested calls that typical Rust error handling (via `Result` and `?`)
+/// is pervasive and has non-trivial cost. Instead, impls of this trait must
+/// implement a delayed error handling strategy. If a failure occurs, they
+/// should record this internally, and all subsequent encoding operations can
+/// be processed or ignored, whichever is appropriate. Then they should provide
+/// a `finish` method that finishes up encoding. If the encoder is fallible,
+/// `finish` should return a `Result` that indicates success or failure.
 pub trait Encoder {
-    type Error;
-
     // Primitive types:
-    fn emit_unit(&mut self) -> Result<(), Self::Error>;
-    fn emit_usize(&mut self, v: usize) -> Result<(), Self::Error>;
-    fn emit_u128(&mut self, v: u128) -> Result<(), Self::Error>;
-    fn emit_u64(&mut self, v: u64) -> Result<(), Self::Error>;
-    fn emit_u32(&mut self, v: u32) -> Result<(), Self::Error>;
-    fn emit_u16(&mut self, v: u16) -> Result<(), Self::Error>;
-    fn emit_u8(&mut self, v: u8) -> Result<(), Self::Error>;
-    fn emit_isize(&mut self, v: isize) -> Result<(), Self::Error>;
-    fn emit_i128(&mut self, v: i128) -> Result<(), Self::Error>;
-    fn emit_i64(&mut self, v: i64) -> Result<(), Self::Error>;
-    fn emit_i32(&mut self, v: i32) -> Result<(), Self::Error>;
-    fn emit_i16(&mut self, v: i16) -> Result<(), Self::Error>;
-    fn emit_i8(&mut self, v: i8) -> Result<(), Self::Error>;
-    fn emit_bool(&mut self, v: bool) -> Result<(), Self::Error>;
-    fn emit_f64(&mut self, v: f64) -> Result<(), Self::Error>;
-    fn emit_f32(&mut self, v: f32) -> Result<(), Self::Error>;
-    fn emit_char(&mut self, v: char) -> Result<(), Self::Error>;
-    fn emit_str(&mut self, v: &str) -> Result<(), Self::Error>;
-    fn emit_raw_bytes(&mut self, s: &[u8]) -> Result<(), Self::Error>;
+    fn emit_usize(&mut self, v: usize);
+    fn emit_u128(&mut self, v: u128);
+    fn emit_u64(&mut self, v: u64);
+    fn emit_u32(&mut self, v: u32);
+    fn emit_u16(&mut self, v: u16);
+    fn emit_u8(&mut self, v: u8);
+    fn emit_isize(&mut self, v: isize);
+    fn emit_i128(&mut self, v: i128);
+    fn emit_i64(&mut self, v: i64);
+    fn emit_i32(&mut self, v: i32);
+    fn emit_i16(&mut self, v: i16);
+    fn emit_i8(&mut self, v: i8);
+    fn emit_bool(&mut self, v: bool);
+    fn emit_f64(&mut self, v: f64);
+    fn emit_f32(&mut self, v: f32);
+    fn emit_char(&mut self, v: char);
+    fn emit_str(&mut self, v: &str);
+    fn emit_raw_bytes(&mut self, s: &[u8]);
 
-    // Compound types:
-    #[inline]
-    fn emit_enum<F>(&mut self, f: F) -> Result<(), Self::Error>
+    // Convenience for the derive macro:
+    fn emit_enum_variant<F>(&mut self, v_id: usize, f: F)
     where
-        F: FnOnce(&mut Self) -> Result<(), Self::Error>,
+        F: FnOnce(&mut Self),
     {
-        f(self)
-    }
-
-    fn emit_enum_variant<F>(
-        &mut self,
-        _v_name: &str,
-        v_id: usize,
-        _len: usize,
-        f: F,
-    ) -> Result<(), Self::Error>
-    where
-        F: FnOnce(&mut Self) -> Result<(), Self::Error>,
-    {
-        self.emit_usize(v_id)?;
-        f(self)
+        self.emit_usize(v_id);
+        f(self);
     }
 
     // We put the field index in a const generic to allow the emit_usize to be
@@ -65,112 +58,9 @@
     // optimization that would otherwise be necessary here, likely due to the
     // multiple levels of inlining and const-prop that are needed.
     #[inline]
-    fn emit_fieldless_enum_variant<const ID: usize>(
-        &mut self,
-        _v_name: &str,
-    ) -> Result<(), Self::Error> {
+    fn emit_fieldless_enum_variant<const ID: usize>(&mut self) {
         self.emit_usize(ID)
     }
-
-    #[inline]
-    fn emit_enum_variant_arg<F>(&mut self, _first: bool, f: F) -> Result<(), Self::Error>
-    where
-        F: FnOnce(&mut Self) -> Result<(), Self::Error>,
-    {
-        f(self)
-    }
-
-    #[inline]
-    fn emit_struct<F>(&mut self, _no_fields: bool, f: F) -> Result<(), Self::Error>
-    where
-        F: FnOnce(&mut Self) -> Result<(), Self::Error>,
-    {
-        f(self)
-    }
-
-    #[inline]
-    fn emit_struct_field<F>(&mut self, _f_name: &str, _first: bool, f: F) -> Result<(), Self::Error>
-    where
-        F: FnOnce(&mut Self) -> Result<(), Self::Error>,
-    {
-        f(self)
-    }
-
-    #[inline]
-    fn emit_tuple<F>(&mut self, _len: usize, f: F) -> Result<(), Self::Error>
-    where
-        F: FnOnce(&mut Self) -> Result<(), Self::Error>,
-    {
-        f(self)
-    }
-
-    #[inline]
-    fn emit_tuple_arg<F>(&mut self, _idx: usize, f: F) -> Result<(), Self::Error>
-    where
-        F: FnOnce(&mut Self) -> Result<(), Self::Error>,
-    {
-        f(self)
-    }
-
-    // Specialized types:
-    fn emit_option<F>(&mut self, f: F) -> Result<(), Self::Error>
-    where
-        F: FnOnce(&mut Self) -> Result<(), Self::Error>,
-    {
-        self.emit_enum(f)
-    }
-
-    #[inline]
-    fn emit_option_none(&mut self) -> Result<(), Self::Error> {
-        self.emit_enum_variant("None", 0, 0, |_| Ok(()))
-    }
-
-    fn emit_option_some<F>(&mut self, f: F) -> Result<(), Self::Error>
-    where
-        F: FnOnce(&mut Self) -> Result<(), Self::Error>,
-    {
-        self.emit_enum_variant("Some", 1, 1, f)
-    }
-
-    fn emit_seq<F>(&mut self, len: usize, f: F) -> Result<(), Self::Error>
-    where
-        F: FnOnce(&mut Self) -> Result<(), Self::Error>,
-    {
-        self.emit_usize(len)?;
-        f(self)
-    }
-
-    #[inline]
-    fn emit_seq_elt<F>(&mut self, _idx: usize, f: F) -> Result<(), Self::Error>
-    where
-        F: FnOnce(&mut Self) -> Result<(), Self::Error>,
-    {
-        f(self)
-    }
-
-    fn emit_map<F>(&mut self, len: usize, f: F) -> Result<(), Self::Error>
-    where
-        F: FnOnce(&mut Self) -> Result<(), Self::Error>,
-    {
-        self.emit_usize(len)?;
-        f(self)
-    }
-
-    #[inline]
-    fn emit_map_elt_key<F>(&mut self, _idx: usize, f: F) -> Result<(), Self::Error>
-    where
-        F: FnOnce(&mut Self) -> Result<(), Self::Error>,
-    {
-        f(self)
-    }
-
-    #[inline]
-    fn emit_map_elt_val<F>(&mut self, f: F) -> Result<(), Self::Error>
-    where
-        F: FnOnce(&mut Self) -> Result<(), Self::Error>,
-    {
-        f(self)
-    }
 }
 
 // Note: all the methods in this trait are infallible, which may be surprising.
@@ -213,7 +103,7 @@
 /// * `TyEncodable` should be used for types that are only serialized in crate
 ///   metadata or the incremental cache. This is most types in `rustc_middle`.
 pub trait Encodable<S: Encoder> {
-    fn encode(&self, s: &mut S) -> Result<(), S::Error>;
+    fn encode(&self, s: &mut S);
 }
 
 /// Trait for types that can be deserialized
@@ -235,8 +125,8 @@
     ($($ty:ident $emit_method:ident $read_method:ident),*) => {
         $(
             impl<S: Encoder> Encodable<S> for $ty {
-                fn encode(&self, s: &mut S) -> Result<(), S::Error> {
-                    s.$emit_method(*self)
+                fn encode(&self, s: &mut S) {
+                    s.$emit_method(*self);
                 }
             }
 
@@ -256,21 +146,32 @@
     u32 emit_u32 read_u32,
     u64 emit_u64 read_u64,
     u128 emit_u128 read_u128,
+
     isize emit_isize read_isize,
     i8 emit_i8 read_i8,
     i16 emit_i16 read_i16,
     i32 emit_i32 read_i32,
     i64 emit_i64 read_i64,
     i128 emit_i128 read_i128,
+
     f32 emit_f32 read_f32,
     f64 emit_f64 read_f64,
     bool emit_bool read_bool,
     char emit_char read_char
 }
 
+impl<S: Encoder, T: ?Sized> Encodable<S> for &T
+where
+    T: Encodable<S>,
+{
+    fn encode(&self, s: &mut S) {
+        (**self).encode(s)
+    }
+}
+
 impl<S: Encoder> Encodable<S> for ! {
-    fn encode(&self, _s: &mut S) -> Result<(), S::Error> {
-        unreachable!()
+    fn encode(&self, _s: &mut S) {
+        unreachable!();
     }
 }
 
@@ -281,8 +182,8 @@
 }
 
 impl<S: Encoder> Encodable<S> for ::std::num::NonZeroU32 {
-    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
-        s.emit_u32(self.get())
+    fn encode(&self, s: &mut S) {
+        s.emit_u32(self.get());
     }
 }
 
@@ -293,20 +194,14 @@
 }
 
 impl<S: Encoder> Encodable<S> for str {
-    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
-        s.emit_str(self)
-    }
-}
-
-impl<S: Encoder> Encodable<S> for &str {
-    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
-        s.emit_str(self)
+    fn encode(&self, s: &mut S) {
+        s.emit_str(self);
     }
 }
 
 impl<S: Encoder> Encodable<S> for String {
-    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
-        s.emit_str(&self[..])
+    fn encode(&self, s: &mut S) {
+        s.emit_str(&self[..]);
     }
 }
 
@@ -317,9 +212,7 @@
 }
 
 impl<S: Encoder> Encodable<S> for () {
-    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
-        s.emit_unit()
-    }
+    fn encode(&self, _s: &mut S) {}
 }
 
 impl<D: Decoder> Decodable<D> for () {
@@ -327,9 +220,7 @@
 }
 
 impl<S: Encoder, T> Encodable<S> for PhantomData<T> {
-    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
-        s.emit_unit()
-    }
+    fn encode(&self, _s: &mut S) {}
 }
 
 impl<D: Decoder, T> Decodable<D> for PhantomData<T> {
@@ -346,8 +237,8 @@
 }
 
 impl<S: Encoder, T: Encodable<S>> Encodable<S> for Rc<T> {
-    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
-        (**self).encode(s)
+    fn encode(&self, s: &mut S) {
+        (**self).encode(s);
     }
 }
 
@@ -358,20 +249,18 @@
 }
 
 impl<S: Encoder, T: Encodable<S>> Encodable<S> for [T] {
-    default fn encode(&self, s: &mut S) -> Result<(), S::Error> {
-        s.emit_seq(self.len(), |s| {
-            for (i, e) in self.iter().enumerate() {
-                s.emit_seq_elt(i, |s| e.encode(s))?
-            }
-            Ok(())
-        })
+    default fn encode(&self, s: &mut S) {
+        s.emit_usize(self.len());
+        for e in self.iter() {
+            e.encode(s);
+        }
     }
 }
 
 impl<S: Encoder, T: Encodable<S>> Encodable<S> for Vec<T> {
-    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
+    fn encode(&self, s: &mut S) {
         let slice: &[T] = self;
-        slice.encode(s)
+        slice.encode(s);
     }
 }
 
@@ -393,9 +282,9 @@
 }
 
 impl<S: Encoder, T: Encodable<S>, const N: usize> Encodable<S> for [T; N] {
-    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
+    fn encode(&self, s: &mut S) {
         let slice: &[T] = self;
-        slice.encode(s)
+        slice.encode(s);
     }
 }
 
@@ -415,9 +304,9 @@
 where
     [T]: ToOwned<Owned = Vec<T>>,
 {
-    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
+    fn encode(&self, s: &mut S) {
         let slice: &[T] = self;
-        slice.encode(s)
+        slice.encode(s);
     }
 }
 
@@ -432,7 +321,7 @@
 }
 
 impl<'a, S: Encoder> Encodable<S> for Cow<'a, str> {
-    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
+    fn encode(&self, s: &mut S) {
         let val: &str = self;
         val.encode(s)
     }
@@ -446,11 +335,11 @@
 }
 
 impl<S: Encoder, T: Encodable<S>> Encodable<S> for Option<T> {
-    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
-        s.emit_option(|s| match *self {
-            None => s.emit_option_none(),
-            Some(ref v) => s.emit_option_some(|s| v.encode(s)),
-        })
+    fn encode(&self, s: &mut S) {
+        match *self {
+            None => s.emit_enum_variant(0, |_| {}),
+            Some(ref v) => s.emit_enum_variant(1, |s| v.encode(s)),
+        }
     }
 }
 
@@ -465,15 +354,11 @@
 }
 
 impl<S: Encoder, T1: Encodable<S>, T2: Encodable<S>> Encodable<S> for Result<T1, T2> {
-    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
-        s.emit_enum(|s| match *self {
-            Ok(ref v) => {
-                s.emit_enum_variant("Ok", 0, 1, |s| s.emit_enum_variant_arg(true, |s| v.encode(s)))
-            }
-            Err(ref v) => {
-                s.emit_enum_variant("Err", 1, 1, |s| s.emit_enum_variant_arg(true, |s| v.encode(s)))
-            }
-        })
+    fn encode(&self, s: &mut S) {
+        match *self {
+            Ok(ref v) => s.emit_enum_variant(0, |s| v.encode(s)),
+            Err(ref v) => s.emit_enum_variant(1, |s| v.encode(s)),
+        }
     }
 }
 
@@ -491,18 +376,6 @@
     ($name:ident, $($other:ident,)*) => (tuple! { $($other,)* })
 }
 
-/// Evaluates to the number of tokens passed to it.
-///
-/// Logarithmic counting: every one or two recursive expansions, the number of
-/// tokens to count is divided by two, instead of being reduced by one.
-/// Therefore, the recursion depth is the binary logarithm of the number of
-/// tokens to count, and the expanded tree is likewise very small.
-macro_rules! count {
-    ($one:tt)              => (1usize);
-    ($($pairs:tt $_p:tt)*) => (count!($($pairs)*) << 1usize);
-    ($odd:tt $($rest:tt)*) => (count!($($rest)*) | 1usize);
-}
-
 macro_rules! tuple {
     () => ();
     ( $($name:ident,)+ ) => (
@@ -513,14 +386,9 @@
         }
         impl<S: Encoder, $($name: Encodable<S>),+> Encodable<S> for ($($name,)+) {
             #[allow(non_snake_case)]
-            fn encode(&self, s: &mut S) -> Result<(), S::Error> {
+            fn encode(&self, s: &mut S) {
                 let ($(ref $name,)+) = *self;
-                let len: usize = count!($($name)+);
-                s.emit_tuple(len, |s| {
-                    let mut i = 0;
-                    $(s.emit_tuple_arg({ i+=1; i-1 }, |s| $name.encode(s))?;)+
-                    Ok(())
-                })
+                $($name.encode(s);)+
             }
         }
         peel! { $($name,)+ }
@@ -530,14 +398,14 @@
 tuple! { T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, }
 
 impl<S: Encoder> Encodable<S> for path::Path {
-    fn encode(&self, e: &mut S) -> Result<(), S::Error> {
-        self.to_str().unwrap().encode(e)
+    fn encode(&self, e: &mut S) {
+        self.to_str().unwrap().encode(e);
     }
 }
 
 impl<S: Encoder> Encodable<S> for path::PathBuf {
-    fn encode(&self, e: &mut S) -> Result<(), S::Error> {
-        path::Path::encode(self, e)
+    fn encode(&self, e: &mut S) {
+        path::Path::encode(self, e);
     }
 }
 
@@ -549,8 +417,8 @@
 }
 
 impl<S: Encoder, T: Encodable<S> + Copy> Encodable<S> for Cell<T> {
-    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
-        self.get().encode(s)
+    fn encode(&self, s: &mut S) {
+        self.get().encode(s);
     }
 }
 
@@ -566,8 +434,8 @@
 // from `encode` when `try_borrow` returns `None`.
 
 impl<S: Encoder, T: Encodable<S>> Encodable<S> for RefCell<T> {
-    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
-        self.borrow().encode(s)
+    fn encode(&self, s: &mut S) {
+        self.borrow().encode(s);
     }
 }
 
@@ -578,8 +446,8 @@
 }
 
 impl<S: Encoder, T: Encodable<S>> Encodable<S> for Arc<T> {
-    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
-        (**self).encode(s)
+    fn encode(&self, s: &mut S) {
+        (**self).encode(s);
     }
 }
 
@@ -590,8 +458,8 @@
 }
 
 impl<S: Encoder, T: ?Sized + Encodable<S>> Encodable<S> for Box<T> {
-    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
-        (**self).encode(s)
+    fn encode(&self, s: &mut S) {
+        (**self).encode(s);
     }
 }
 impl<D: Decoder, T: Decodable<D>> Decodable<D> for Box<T> {
diff --git a/compiler/rustc_serialize/tests/json.rs b/compiler/rustc_serialize/tests/json.rs
deleted file mode 100644
index 944fe46..0000000
--- a/compiler/rustc_serialize/tests/json.rs
+++ /dev/null
@@ -1,978 +0,0 @@
-#![allow(rustc::internal)]
-
-use json::ErrorCode::*;
-use json::Json::*;
-use json::JsonEvent::*;
-use json::ParserError::*;
-use json::{from_str, Encoder, EncoderError, Json, JsonEvent, Parser, StackElement};
-use rustc_macros::Encodable;
-use rustc_serialize::json;
-use rustc_serialize::Encodable;
-
-use std::collections::BTreeMap;
-use std::io::prelude::*;
-use std::string;
-use Animal::*;
-
-#[derive(Eq, PartialEq, Debug)]
-struct OptionData {
-    opt: Option<usize>,
-}
-
-#[derive(PartialEq, Encodable, Debug)]
-enum Animal {
-    Dog,
-    Frog(string::String, isize),
-}
-
-#[derive(PartialEq, Encodable, Debug)]
-struct Inner {
-    a: (),
-    b: usize,
-    c: Vec<string::String>,
-}
-
-#[derive(PartialEq, Encodable, Debug)]
-struct Outer {
-    inner: Vec<Inner>,
-}
-
-fn mk_object(items: &[(string::String, Json)]) -> Json {
-    let mut d = BTreeMap::new();
-
-    for item in items {
-        match *item {
-            (ref key, ref value) => {
-                d.insert((*key).clone(), (*value).clone());
-            }
-        }
-    }
-
-    Object(d)
-}
-
-#[test]
-fn test_from_str_trait() {
-    let s = "null";
-    assert!(s.parse::<Json>().unwrap() == s.parse().unwrap());
-}
-
-#[test]
-fn test_write_null() {
-    assert_eq!(Null.to_string(), "null");
-    assert_eq!(Null.pretty().to_string(), "null");
-}
-
-#[test]
-fn test_write_i64() {
-    assert_eq!(U64(0).to_string(), "0");
-    assert_eq!(U64(0).pretty().to_string(), "0");
-
-    assert_eq!(U64(1234).to_string(), "1234");
-    assert_eq!(U64(1234).pretty().to_string(), "1234");
-
-    assert_eq!(I64(-5678).to_string(), "-5678");
-    assert_eq!(I64(-5678).pretty().to_string(), "-5678");
-
-    assert_eq!(U64(7650007200025252000).to_string(), "7650007200025252000");
-    assert_eq!(U64(7650007200025252000).pretty().to_string(), "7650007200025252000");
-}
-
-#[test]
-fn test_write_f64() {
-    assert_eq!(F64(3.0).to_string(), "3.0");
-    assert_eq!(F64(3.0).pretty().to_string(), "3.0");
-
-    assert_eq!(F64(3.1).to_string(), "3.1");
-    assert_eq!(F64(3.1).pretty().to_string(), "3.1");
-
-    assert_eq!(F64(-1.5).to_string(), "-1.5");
-    assert_eq!(F64(-1.5).pretty().to_string(), "-1.5");
-
-    assert_eq!(F64(0.5).to_string(), "0.5");
-    assert_eq!(F64(0.5).pretty().to_string(), "0.5");
-
-    assert_eq!(F64(f64::NAN).to_string(), "null");
-    assert_eq!(F64(f64::NAN).pretty().to_string(), "null");
-
-    assert_eq!(F64(f64::INFINITY).to_string(), "null");
-    assert_eq!(F64(f64::INFINITY).pretty().to_string(), "null");
-
-    assert_eq!(F64(f64::NEG_INFINITY).to_string(), "null");
-    assert_eq!(F64(f64::NEG_INFINITY).pretty().to_string(), "null");
-}
-
-#[test]
-fn test_write_str() {
-    assert_eq!(String("".to_string()).to_string(), "\"\"");
-    assert_eq!(String("".to_string()).pretty().to_string(), "\"\"");
-
-    assert_eq!(String("homura".to_string()).to_string(), "\"homura\"");
-    assert_eq!(String("madoka".to_string()).pretty().to_string(), "\"madoka\"");
-}
-
-#[test]
-fn test_write_bool() {
-    assert_eq!(Boolean(true).to_string(), "true");
-    assert_eq!(Boolean(true).pretty().to_string(), "true");
-
-    assert_eq!(Boolean(false).to_string(), "false");
-    assert_eq!(Boolean(false).pretty().to_string(), "false");
-}
-
-#[test]
-fn test_write_array() {
-    assert_eq!(Array(vec![]).to_string(), "[]");
-    assert_eq!(Array(vec![]).pretty().to_string(), "[]");
-
-    assert_eq!(Array(vec![Boolean(true)]).to_string(), "[true]");
-    assert_eq!(
-        Array(vec![Boolean(true)]).pretty().to_string(),
-        "\
-        [\n  \
-            true\n\
-        ]"
-    );
-
-    let long_test_array =
-        Array(vec![Boolean(false), Null, Array(vec![String("foo\nbar".to_string()), F64(3.5)])]);
-
-    assert_eq!(long_test_array.to_string(), "[false,null,[\"foo\\nbar\",3.5]]");
-    assert_eq!(
-        long_test_array.pretty().to_string(),
-        "\
-        [\n  \
-            false,\n  \
-            null,\n  \
-            [\n    \
-                \"foo\\nbar\",\n    \
-                3.5\n  \
-            ]\n\
-        ]"
-    );
-}
-
-#[test]
-fn test_write_object() {
-    assert_eq!(mk_object(&[]).to_string(), "{}");
-    assert_eq!(mk_object(&[]).pretty().to_string(), "{}");
-
-    assert_eq!(mk_object(&[("a".to_string(), Boolean(true))]).to_string(), "{\"a\":true}");
-    assert_eq!(
-        mk_object(&[("a".to_string(), Boolean(true))]).pretty().to_string(),
-        "\
-        {\n  \
-            \"a\": true\n\
-        }"
-    );
-
-    let complex_obj = mk_object(&[(
-        "b".to_string(),
-        Array(vec![
-            mk_object(&[("c".to_string(), String("\x0c\r".to_string()))]),
-            mk_object(&[("d".to_string(), String("".to_string()))]),
-        ]),
-    )]);
-
-    assert_eq!(
-        complex_obj.to_string(),
-        "{\
-            \"b\":[\
-                {\"c\":\"\\f\\r\"},\
-                {\"d\":\"\"}\
-            ]\
-        }"
-    );
-    assert_eq!(
-        complex_obj.pretty().to_string(),
-        "\
-        {\n  \
-            \"b\": [\n    \
-                {\n      \
-                    \"c\": \"\\f\\r\"\n    \
-                },\n    \
-                {\n      \
-                    \"d\": \"\"\n    \
-                }\n  \
-            ]\n\
-        }"
-    );
-
-    let a = mk_object(&[
-        ("a".to_string(), Boolean(true)),
-        (
-            "b".to_string(),
-            Array(vec![
-                mk_object(&[("c".to_string(), String("\x0c\r".to_string()))]),
-                mk_object(&[("d".to_string(), String("".to_string()))]),
-            ]),
-        ),
-    ]);
-
-    // We can't compare the strings directly because the object fields be
-    // printed in a different order.
-    assert_eq!(a.clone(), a.to_string().parse().unwrap());
-    assert_eq!(a.clone(), a.pretty().to_string().parse().unwrap());
-}
-
-#[test]
-fn test_write_enum() {
-    let animal = Dog;
-    assert_eq!(json::as_json(&animal).to_string(), "\"Dog\"");
-    assert_eq!(json::as_pretty_json(&animal).to_string(), "\"Dog\"");
-
-    let animal = Frog("Henry".to_string(), 349);
-    assert_eq!(
-        json::as_json(&animal).to_string(),
-        "{\"variant\":\"Frog\",\"fields\":[\"Henry\",349]}"
-    );
-    assert_eq!(
-        json::as_pretty_json(&animal).to_string(),
-        "{\n  \
-           \"variant\": \"Frog\",\n  \
-           \"fields\": [\n    \
-             \"Henry\",\n    \
-             349\n  \
-           ]\n\
-         }"
-    );
-}
-
-macro_rules! check_encoder_for_simple {
-    ($value:expr, $expected:expr) => {{
-        let s = json::as_json(&$value).to_string();
-        assert_eq!(s, $expected);
-
-        let s = json::as_pretty_json(&$value).to_string();
-        assert_eq!(s, $expected);
-    }};
-}
-
-#[test]
-fn test_write_some() {
-    check_encoder_for_simple!(Some("jodhpurs".to_string()), "\"jodhpurs\"");
-}
-
-#[test]
-fn test_write_none() {
-    check_encoder_for_simple!(None::<string::String>, "null");
-}
-
-#[test]
-fn test_write_char() {
-    check_encoder_for_simple!('a', "\"a\"");
-    check_encoder_for_simple!('\t', "\"\\t\"");
-    check_encoder_for_simple!('\u{0000}', "\"\\u0000\"");
-    check_encoder_for_simple!('\u{001b}', "\"\\u001b\"");
-    check_encoder_for_simple!('\u{007f}', "\"\\u007f\"");
-    check_encoder_for_simple!('\u{00a0}', "\"\u{00a0}\"");
-    check_encoder_for_simple!('\u{abcd}', "\"\u{abcd}\"");
-    check_encoder_for_simple!('\u{10ffff}', "\"\u{10ffff}\"");
-}
-
-#[test]
-fn test_trailing_characters() {
-    assert_eq!(from_str("nulla"), Err(SyntaxError(TrailingCharacters, 1, 5)));
-    assert_eq!(from_str("truea"), Err(SyntaxError(TrailingCharacters, 1, 5)));
-    assert_eq!(from_str("falsea"), Err(SyntaxError(TrailingCharacters, 1, 6)));
-    assert_eq!(from_str("1a"), Err(SyntaxError(TrailingCharacters, 1, 2)));
-    assert_eq!(from_str("[]a"), Err(SyntaxError(TrailingCharacters, 1, 3)));
-    assert_eq!(from_str("{}a"), Err(SyntaxError(TrailingCharacters, 1, 3)));
-}
-
-#[test]
-fn test_read_identifiers() {
-    assert_eq!(from_str("n"), Err(SyntaxError(InvalidSyntax, 1, 2)));
-    assert_eq!(from_str("nul"), Err(SyntaxError(InvalidSyntax, 1, 4)));
-    assert_eq!(from_str("t"), Err(SyntaxError(InvalidSyntax, 1, 2)));
-    assert_eq!(from_str("truz"), Err(SyntaxError(InvalidSyntax, 1, 4)));
-    assert_eq!(from_str("f"), Err(SyntaxError(InvalidSyntax, 1, 2)));
-    assert_eq!(from_str("faz"), Err(SyntaxError(InvalidSyntax, 1, 3)));
-
-    assert_eq!(from_str("null"), Ok(Null));
-    assert_eq!(from_str("true"), Ok(Boolean(true)));
-    assert_eq!(from_str("false"), Ok(Boolean(false)));
-    assert_eq!(from_str(" null "), Ok(Null));
-    assert_eq!(from_str(" true "), Ok(Boolean(true)));
-    assert_eq!(from_str(" false "), Ok(Boolean(false)));
-}
-
-#[test]
-fn test_read_number() {
-    assert_eq!(from_str("+"), Err(SyntaxError(InvalidSyntax, 1, 1)));
-    assert_eq!(from_str("."), Err(SyntaxError(InvalidSyntax, 1, 1)));
-    assert_eq!(from_str("NaN"), Err(SyntaxError(InvalidSyntax, 1, 1)));
-    assert_eq!(from_str("-"), Err(SyntaxError(InvalidNumber, 1, 2)));
-    assert_eq!(from_str("00"), Err(SyntaxError(InvalidNumber, 1, 2)));
-    assert_eq!(from_str("1."), Err(SyntaxError(InvalidNumber, 1, 3)));
-    assert_eq!(from_str("1e"), Err(SyntaxError(InvalidNumber, 1, 3)));
-    assert_eq!(from_str("1e+"), Err(SyntaxError(InvalidNumber, 1, 4)));
-
-    assert_eq!(from_str("18446744073709551616"), Err(SyntaxError(InvalidNumber, 1, 20)));
-    assert_eq!(from_str("-9223372036854775809"), Err(SyntaxError(InvalidNumber, 1, 21)));
-
-    assert_eq!(from_str("3"), Ok(U64(3)));
-    assert_eq!(from_str("3.1"), Ok(F64(3.1)));
-    assert_eq!(from_str("-1.2"), Ok(F64(-1.2)));
-    assert_eq!(from_str("0.4"), Ok(F64(0.4)));
-    assert_eq!(from_str("0.4e5"), Ok(F64(0.4e5)));
-    assert_eq!(from_str("0.4e+15"), Ok(F64(0.4e15)));
-    assert_eq!(from_str("0.4e-01"), Ok(F64(0.4e-01)));
-    assert_eq!(from_str(" 3 "), Ok(U64(3)));
-
-    assert_eq!(from_str("-9223372036854775808"), Ok(I64(i64::MIN)));
-    assert_eq!(from_str("9223372036854775807"), Ok(U64(i64::MAX as u64)));
-    assert_eq!(from_str("18446744073709551615"), Ok(U64(u64::MAX)));
-}
-
-#[test]
-fn test_read_str() {
-    assert_eq!(from_str("\""), Err(SyntaxError(EOFWhileParsingString, 1, 2)));
-    assert_eq!(from_str("\"lol"), Err(SyntaxError(EOFWhileParsingString, 1, 5)));
-
-    assert_eq!(from_str("\"\""), Ok(String("".to_string())));
-    assert_eq!(from_str("\"foo\""), Ok(String("foo".to_string())));
-    assert_eq!(from_str("\"\\\"\""), Ok(String("\"".to_string())));
-    assert_eq!(from_str("\"\\b\""), Ok(String("\x08".to_string())));
-    assert_eq!(from_str("\"\\n\""), Ok(String("\n".to_string())));
-    assert_eq!(from_str("\"\\r\""), Ok(String("\r".to_string())));
-    assert_eq!(from_str("\"\\t\""), Ok(String("\t".to_string())));
-    assert_eq!(from_str(" \"foo\" "), Ok(String("foo".to_string())));
-    assert_eq!(from_str("\"\\u12ab\""), Ok(String("\u{12ab}".to_string())));
-    assert_eq!(from_str("\"\\uAB12\""), Ok(String("\u{AB12}".to_string())));
-}
-
-#[test]
-fn test_read_array() {
-    assert_eq!(from_str("["), Err(SyntaxError(EOFWhileParsingValue, 1, 2)));
-    assert_eq!(from_str("[1"), Err(SyntaxError(EOFWhileParsingArray, 1, 3)));
-    assert_eq!(from_str("[1,"), Err(SyntaxError(EOFWhileParsingValue, 1, 4)));
-    assert_eq!(from_str("[1,]"), Err(SyntaxError(InvalidSyntax, 1, 4)));
-    assert_eq!(from_str("[6 7]"), Err(SyntaxError(InvalidSyntax, 1, 4)));
-
-    assert_eq!(from_str("[]"), Ok(Array(vec![])));
-    assert_eq!(from_str("[ ]"), Ok(Array(vec![])));
-    assert_eq!(from_str("[true]"), Ok(Array(vec![Boolean(true)])));
-    assert_eq!(from_str("[ false ]"), Ok(Array(vec![Boolean(false)])));
-    assert_eq!(from_str("[null]"), Ok(Array(vec![Null])));
-    assert_eq!(from_str("[3, 1]"), Ok(Array(vec![U64(3), U64(1)])));
-    assert_eq!(from_str("\n[3, 2]\n"), Ok(Array(vec![U64(3), U64(2)])));
-    assert_eq!(from_str("[2, [4, 1]]"), Ok(Array(vec![U64(2), Array(vec![U64(4), U64(1)])])));
-}
-
-#[test]
-fn test_read_object() {
-    assert_eq!(from_str("{"), Err(SyntaxError(EOFWhileParsingObject, 1, 2)));
-    assert_eq!(from_str("{ "), Err(SyntaxError(EOFWhileParsingObject, 1, 3)));
-    assert_eq!(from_str("{1"), Err(SyntaxError(KeyMustBeAString, 1, 2)));
-    assert_eq!(from_str("{ \"a\""), Err(SyntaxError(EOFWhileParsingObject, 1, 6)));
-    assert_eq!(from_str("{\"a\""), Err(SyntaxError(EOFWhileParsingObject, 1, 5)));
-    assert_eq!(from_str("{\"a\" "), Err(SyntaxError(EOFWhileParsingObject, 1, 6)));
-
-    assert_eq!(from_str("{\"a\" 1"), Err(SyntaxError(ExpectedColon, 1, 6)));
-    assert_eq!(from_str("{\"a\":"), Err(SyntaxError(EOFWhileParsingValue, 1, 6)));
-    assert_eq!(from_str("{\"a\":1"), Err(SyntaxError(EOFWhileParsingObject, 1, 7)));
-    assert_eq!(from_str("{\"a\":1 1"), Err(SyntaxError(InvalidSyntax, 1, 8)));
-    assert_eq!(from_str("{\"a\":1,"), Err(SyntaxError(EOFWhileParsingObject, 1, 8)));
-
-    assert_eq!(from_str("{}").unwrap(), mk_object(&[]));
-    assert_eq!(from_str("{\"a\": 3}").unwrap(), mk_object(&[("a".to_string(), U64(3))]));
-
-    assert_eq!(
-        from_str("{ \"a\": null, \"b\" : true }").unwrap(),
-        mk_object(&[("a".to_string(), Null), ("b".to_string(), Boolean(true))])
-    );
-    assert_eq!(
-        from_str("\n{ \"a\": null, \"b\" : true }\n").unwrap(),
-        mk_object(&[("a".to_string(), Null), ("b".to_string(), Boolean(true))])
-    );
-    assert_eq!(
-        from_str("{\"a\" : 1.0 ,\"b\": [ true ]}").unwrap(),
-        mk_object(&[("a".to_string(), F64(1.0)), ("b".to_string(), Array(vec![Boolean(true)]))])
-    );
-    assert_eq!(
-        from_str(
-            "{\
-                        \"a\": 1.0, \
-                        \"b\": [\
-                            true,\
-                            \"foo\\nbar\", \
-                            { \"c\": {\"d\": null} } \
-                        ]\
-                    }"
-        )
-        .unwrap(),
-        mk_object(&[
-            ("a".to_string(), F64(1.0)),
-            (
-                "b".to_string(),
-                Array(vec![
-                    Boolean(true),
-                    String("foo\nbar".to_string()),
-                    mk_object(&[("c".to_string(), mk_object(&[("d".to_string(), Null)]))])
-                ])
-            )
-        ])
-    );
-}
-
-#[test]
-fn test_multiline_errors() {
-    assert_eq!(from_str("{\n  \"foo\":\n \"bar\""), Err(SyntaxError(EOFWhileParsingObject, 3, 8)));
-}
-
-#[test]
-fn test_find() {
-    let json_value = from_str("{\"dog\" : \"cat\"}").unwrap();
-    let found_str = json_value.find("dog");
-    assert!(found_str.unwrap().as_string().unwrap() == "cat");
-}
-
-#[test]
-fn test_find_path() {
-    let json_value = from_str("{\"dog\":{\"cat\": {\"mouse\" : \"cheese\"}}}").unwrap();
-    let found_str = json_value.find_path(&["dog", "cat", "mouse"]);
-    assert!(found_str.unwrap().as_string().unwrap() == "cheese");
-}
-
-#[test]
-fn test_search() {
-    let json_value = from_str("{\"dog\":{\"cat\": {\"mouse\" : \"cheese\"}}}").unwrap();
-    let found_str = json_value.search("mouse").and_then(|j| j.as_string());
-    assert!(found_str.unwrap() == "cheese");
-}
-
-#[test]
-fn test_index() {
-    let json_value = from_str("{\"animals\":[\"dog\",\"cat\",\"mouse\"]}").unwrap();
-    let ref array = json_value["animals"];
-    assert_eq!(array[0].as_string().unwrap(), "dog");
-    assert_eq!(array[1].as_string().unwrap(), "cat");
-    assert_eq!(array[2].as_string().unwrap(), "mouse");
-}
-
-#[test]
-fn test_is_object() {
-    let json_value = from_str("{}").unwrap();
-    assert!(json_value.is_object());
-}
-
-#[test]
-fn test_as_object() {
-    let json_value = from_str("{}").unwrap();
-    let json_object = json_value.as_object();
-    assert!(json_object.is_some());
-}
-
-#[test]
-fn test_is_array() {
-    let json_value = from_str("[1, 2, 3]").unwrap();
-    assert!(json_value.is_array());
-}
-
-#[test]
-fn test_as_array() {
-    let json_value = from_str("[1, 2, 3]").unwrap();
-    let json_array = json_value.as_array();
-    let expected_length = 3;
-    assert!(json_array.is_some() && json_array.unwrap().len() == expected_length);
-}
-
-#[test]
-fn test_is_string() {
-    let json_value = from_str("\"dog\"").unwrap();
-    assert!(json_value.is_string());
-}
-
-#[test]
-fn test_as_string() {
-    let json_value = from_str("\"dog\"").unwrap();
-    let json_str = json_value.as_string();
-    let expected_str = "dog";
-    assert_eq!(json_str, Some(expected_str));
-}
-
-#[test]
-fn test_is_number() {
-    let json_value = from_str("12").unwrap();
-    assert!(json_value.is_number());
-}
-
-#[test]
-fn test_is_i64() {
-    let json_value = from_str("-12").unwrap();
-    assert!(json_value.is_i64());
-
-    let json_value = from_str("12").unwrap();
-    assert!(!json_value.is_i64());
-
-    let json_value = from_str("12.0").unwrap();
-    assert!(!json_value.is_i64());
-}
-
-#[test]
-fn test_is_u64() {
-    let json_value = from_str("12").unwrap();
-    assert!(json_value.is_u64());
-
-    let json_value = from_str("-12").unwrap();
-    assert!(!json_value.is_u64());
-
-    let json_value = from_str("12.0").unwrap();
-    assert!(!json_value.is_u64());
-}
-
-#[test]
-fn test_is_f64() {
-    let json_value = from_str("12").unwrap();
-    assert!(!json_value.is_f64());
-
-    let json_value = from_str("-12").unwrap();
-    assert!(!json_value.is_f64());
-
-    let json_value = from_str("12.0").unwrap();
-    assert!(json_value.is_f64());
-
-    let json_value = from_str("-12.0").unwrap();
-    assert!(json_value.is_f64());
-}
-
-#[test]
-fn test_as_i64() {
-    let json_value = from_str("-12").unwrap();
-    let json_num = json_value.as_i64();
-    assert_eq!(json_num, Some(-12));
-}
-
-#[test]
-fn test_as_u64() {
-    let json_value = from_str("12").unwrap();
-    let json_num = json_value.as_u64();
-    assert_eq!(json_num, Some(12));
-}
-
-#[test]
-fn test_as_f64() {
-    let json_value = from_str("12.0").unwrap();
-    let json_num = json_value.as_f64();
-    assert_eq!(json_num, Some(12f64));
-}
-
-#[test]
-fn test_is_boolean() {
-    let json_value = from_str("false").unwrap();
-    assert!(json_value.is_boolean());
-}
-
-#[test]
-fn test_as_boolean() {
-    let json_value = from_str("false").unwrap();
-    let json_bool = json_value.as_boolean();
-    let expected_bool = false;
-    assert!(json_bool.is_some() && json_bool.unwrap() == expected_bool);
-}
-
-#[test]
-fn test_is_null() {
-    let json_value = from_str("null").unwrap();
-    assert!(json_value.is_null());
-}
-
-#[test]
-fn test_as_null() {
-    let json_value = from_str("null").unwrap();
-    let json_null = json_value.as_null();
-    let expected_null = ();
-    assert!(json_null.is_some() && json_null.unwrap() == expected_null);
-}
-
-#[test]
-fn test_encode_hashmap_with_numeric_key() {
-    use std::collections::HashMap;
-    use std::str::from_utf8;
-    let mut hm: HashMap<usize, bool> = HashMap::new();
-    hm.insert(1, true);
-    let mut mem_buf = Vec::new();
-    write!(&mut mem_buf, "{}", json::as_pretty_json(&hm)).unwrap();
-    let json_str = from_utf8(&mem_buf[..]).unwrap();
-    match from_str(json_str) {
-        Err(_) => panic!("Unable to parse json_str: {:?}", json_str),
-        _ => {} // it parsed and we are good to go
-    }
-}
-
-#[test]
-fn test_prettyencode_hashmap_with_numeric_key() {
-    use std::collections::HashMap;
-    use std::str::from_utf8;
-    let mut hm: HashMap<usize, bool> = HashMap::new();
-    hm.insert(1, true);
-    let mut mem_buf = Vec::new();
-    write!(&mut mem_buf, "{}", json::as_pretty_json(&hm)).unwrap();
-    let json_str = from_utf8(&mem_buf[..]).unwrap();
-    match from_str(json_str) {
-        Err(_) => panic!("Unable to parse json_str: {:?}", json_str),
-        _ => {} // it parsed and we are good to go
-    }
-}
-
-#[test]
-fn test_prettyencoder_indent_level_param() {
-    use std::collections::BTreeMap;
-    use std::str::from_utf8;
-
-    let mut tree = BTreeMap::new();
-
-    tree.insert("hello".to_string(), String("guten tag".to_string()));
-    tree.insert("goodbye".to_string(), String("sayonara".to_string()));
-
-    let json = Array(
-        // The following layout below should look a lot like
-        // the pretty-printed JSON (indent * x)
-        vec![
-            // 0x
-            String("greetings".to_string()), // 1x
-            Object(tree),                    // 1x + 2x + 2x + 1x
-        ], // 0x
-           // End JSON array (7 lines)
-    );
-
-    // Helper function for counting indents
-    fn indents(source: &str) -> usize {
-        let trimmed = source.trim_start_matches(' ');
-        source.len() - trimmed.len()
-    }
-
-    // Test up to 4 spaces of indents (more?)
-    for i in 0..4 {
-        let mut writer = Vec::new();
-        write!(&mut writer, "{}", json::as_pretty_json(&json).indent(i)).unwrap();
-
-        let printed = from_utf8(&writer[..]).unwrap();
-
-        // Check for indents at each line
-        let lines: Vec<&str> = printed.lines().collect();
-        assert_eq!(lines.len(), 7); // JSON should be 7 lines
-
-        assert_eq!(indents(lines[0]), 0 * i); // [
-        assert_eq!(indents(lines[1]), 1 * i); //   "greetings",
-        assert_eq!(indents(lines[2]), 1 * i); //   {
-        assert_eq!(indents(lines[3]), 2 * i); //     "hello": "guten tag",
-        assert_eq!(indents(lines[4]), 2 * i); //     "goodbye": "sayonara"
-        assert_eq!(indents(lines[5]), 1 * i); //   },
-        assert_eq!(indents(lines[6]), 0 * i); // ]
-
-        // Finally, test that the pretty-printed JSON is valid
-        from_str(printed).ok().expect("Pretty-printed JSON is invalid!");
-    }
-}
-
-#[test]
-fn test_hashmap_with_enum_key() {
-    use std::collections::HashMap;
-    #[derive(Encodable, Eq, Hash, PartialEq, Debug)]
-    enum Enum {
-        Foo,
-        #[allow(dead_code)]
-        Bar,
-    }
-    let mut map = HashMap::new();
-    map.insert(Enum::Foo, 0);
-    let result = json::encode(&map).unwrap();
-    assert_eq!(&result[..], r#"{"Foo":0}"#);
-}
-
-fn assert_stream_equal(src: &str, expected: Vec<(JsonEvent, Vec<StackElement<'_>>)>) {
-    let mut parser = Parser::new(src.chars());
-    let mut i = 0;
-    loop {
-        let evt = match parser.next() {
-            Some(e) => e,
-            None => {
-                break;
-            }
-        };
-        let (ref expected_evt, ref expected_stack) = expected[i];
-        if !parser.stack().is_equal_to(expected_stack) {
-            panic!("Parser stack is not equal to {:?}", expected_stack);
-        }
-        assert_eq!(&evt, expected_evt);
-        i += 1;
-    }
-}
-#[test]
-fn test_streaming_parser() {
-    assert_stream_equal(
-        r#"{ "foo":"bar", "array" : [0, 1, 2, 3, 4, 5], "idents":[null,true,false]}"#,
-        vec![
-            (ObjectStart, vec![]),
-            (StringValue("bar".to_string()), vec![StackElement::Key("foo")]),
-            (ArrayStart, vec![StackElement::Key("array")]),
-            (U64Value(0), vec![StackElement::Key("array"), StackElement::Index(0)]),
-            (U64Value(1), vec![StackElement::Key("array"), StackElement::Index(1)]),
-            (U64Value(2), vec![StackElement::Key("array"), StackElement::Index(2)]),
-            (U64Value(3), vec![StackElement::Key("array"), StackElement::Index(3)]),
-            (U64Value(4), vec![StackElement::Key("array"), StackElement::Index(4)]),
-            (U64Value(5), vec![StackElement::Key("array"), StackElement::Index(5)]),
-            (ArrayEnd, vec![StackElement::Key("array")]),
-            (ArrayStart, vec![StackElement::Key("idents")]),
-            (NullValue, vec![StackElement::Key("idents"), StackElement::Index(0)]),
-            (BooleanValue(true), vec![StackElement::Key("idents"), StackElement::Index(1)]),
-            (BooleanValue(false), vec![StackElement::Key("idents"), StackElement::Index(2)]),
-            (ArrayEnd, vec![StackElement::Key("idents")]),
-            (ObjectEnd, vec![]),
-        ],
-    );
-}
-fn last_event(src: &str) -> JsonEvent {
-    let mut parser = Parser::new(src.chars());
-    let mut evt = NullValue;
-    loop {
-        evt = match parser.next() {
-            Some(e) => e,
-            None => return evt,
-        }
-    }
-}
-
-#[test]
-fn test_read_object_streaming() {
-    assert_eq!(last_event("{ "), Error(SyntaxError(EOFWhileParsingObject, 1, 3)));
-    assert_eq!(last_event("{1"), Error(SyntaxError(KeyMustBeAString, 1, 2)));
-    assert_eq!(last_event("{ \"a\""), Error(SyntaxError(EOFWhileParsingObject, 1, 6)));
-    assert_eq!(last_event("{\"a\""), Error(SyntaxError(EOFWhileParsingObject, 1, 5)));
-    assert_eq!(last_event("{\"a\" "), Error(SyntaxError(EOFWhileParsingObject, 1, 6)));
-
-    assert_eq!(last_event("{\"a\" 1"), Error(SyntaxError(ExpectedColon, 1, 6)));
-    assert_eq!(last_event("{\"a\":"), Error(SyntaxError(EOFWhileParsingValue, 1, 6)));
-    assert_eq!(last_event("{\"a\":1"), Error(SyntaxError(EOFWhileParsingObject, 1, 7)));
-    assert_eq!(last_event("{\"a\":1 1"), Error(SyntaxError(InvalidSyntax, 1, 8)));
-    assert_eq!(last_event("{\"a\":1,"), Error(SyntaxError(EOFWhileParsingObject, 1, 8)));
-    assert_eq!(last_event("{\"a\":1,}"), Error(SyntaxError(TrailingComma, 1, 8)));
-
-    assert_stream_equal("{}", vec![(ObjectStart, vec![]), (ObjectEnd, vec![])]);
-    assert_stream_equal(
-        "{\"a\": 3}",
-        vec![
-            (ObjectStart, vec![]),
-            (U64Value(3), vec![StackElement::Key("a")]),
-            (ObjectEnd, vec![]),
-        ],
-    );
-    assert_stream_equal(
-        "{ \"a\": null, \"b\" : true }",
-        vec![
-            (ObjectStart, vec![]),
-            (NullValue, vec![StackElement::Key("a")]),
-            (BooleanValue(true), vec![StackElement::Key("b")]),
-            (ObjectEnd, vec![]),
-        ],
-    );
-    assert_stream_equal(
-        "{\"a\" : 1.0 ,\"b\": [ true ]}",
-        vec![
-            (ObjectStart, vec![]),
-            (F64Value(1.0), vec![StackElement::Key("a")]),
-            (ArrayStart, vec![StackElement::Key("b")]),
-            (BooleanValue(true), vec![StackElement::Key("b"), StackElement::Index(0)]),
-            (ArrayEnd, vec![StackElement::Key("b")]),
-            (ObjectEnd, vec![]),
-        ],
-    );
-    assert_stream_equal(
-        r#"{
-            "a": 1.0,
-            "b": [
-                true,
-                "foo\nbar",
-                { "c": {"d": null} }
-            ]
-        }"#,
-        vec![
-            (ObjectStart, vec![]),
-            (F64Value(1.0), vec![StackElement::Key("a")]),
-            (ArrayStart, vec![StackElement::Key("b")]),
-            (BooleanValue(true), vec![StackElement::Key("b"), StackElement::Index(0)]),
-            (
-                StringValue("foo\nbar".to_string()),
-                vec![StackElement::Key("b"), StackElement::Index(1)],
-            ),
-            (ObjectStart, vec![StackElement::Key("b"), StackElement::Index(2)]),
-            (
-                ObjectStart,
-                vec![StackElement::Key("b"), StackElement::Index(2), StackElement::Key("c")],
-            ),
-            (
-                NullValue,
-                vec![
-                    StackElement::Key("b"),
-                    StackElement::Index(2),
-                    StackElement::Key("c"),
-                    StackElement::Key("d"),
-                ],
-            ),
-            (
-                ObjectEnd,
-                vec![StackElement::Key("b"), StackElement::Index(2), StackElement::Key("c")],
-            ),
-            (ObjectEnd, vec![StackElement::Key("b"), StackElement::Index(2)]),
-            (ArrayEnd, vec![StackElement::Key("b")]),
-            (ObjectEnd, vec![]),
-        ],
-    );
-}
-#[test]
-fn test_read_array_streaming() {
-    assert_stream_equal("[]", vec![(ArrayStart, vec![]), (ArrayEnd, vec![])]);
-    assert_stream_equal("[ ]", vec![(ArrayStart, vec![]), (ArrayEnd, vec![])]);
-    assert_stream_equal(
-        "[true]",
-        vec![
-            (ArrayStart, vec![]),
-            (BooleanValue(true), vec![StackElement::Index(0)]),
-            (ArrayEnd, vec![]),
-        ],
-    );
-    assert_stream_equal(
-        "[ false ]",
-        vec![
-            (ArrayStart, vec![]),
-            (BooleanValue(false), vec![StackElement::Index(0)]),
-            (ArrayEnd, vec![]),
-        ],
-    );
-    assert_stream_equal(
-        "[null]",
-        vec![(ArrayStart, vec![]), (NullValue, vec![StackElement::Index(0)]), (ArrayEnd, vec![])],
-    );
-    assert_stream_equal(
-        "[3, 1]",
-        vec![
-            (ArrayStart, vec![]),
-            (U64Value(3), vec![StackElement::Index(0)]),
-            (U64Value(1), vec![StackElement::Index(1)]),
-            (ArrayEnd, vec![]),
-        ],
-    );
-    assert_stream_equal(
-        "\n[3, 2]\n",
-        vec![
-            (ArrayStart, vec![]),
-            (U64Value(3), vec![StackElement::Index(0)]),
-            (U64Value(2), vec![StackElement::Index(1)]),
-            (ArrayEnd, vec![]),
-        ],
-    );
-    assert_stream_equal(
-        "[2, [4, 1]]",
-        vec![
-            (ArrayStart, vec![]),
-            (U64Value(2), vec![StackElement::Index(0)]),
-            (ArrayStart, vec![StackElement::Index(1)]),
-            (U64Value(4), vec![StackElement::Index(1), StackElement::Index(0)]),
-            (U64Value(1), vec![StackElement::Index(1), StackElement::Index(1)]),
-            (ArrayEnd, vec![StackElement::Index(1)]),
-            (ArrayEnd, vec![]),
-        ],
-    );
-
-    assert_eq!(last_event("["), Error(SyntaxError(EOFWhileParsingValue, 1, 2)));
-
-    assert_eq!(from_str("["), Err(SyntaxError(EOFWhileParsingValue, 1, 2)));
-    assert_eq!(from_str("[1"), Err(SyntaxError(EOFWhileParsingArray, 1, 3)));
-    assert_eq!(from_str("[1,"), Err(SyntaxError(EOFWhileParsingValue, 1, 4)));
-    assert_eq!(from_str("[1,]"), Err(SyntaxError(InvalidSyntax, 1, 4)));
-    assert_eq!(from_str("[6 7]"), Err(SyntaxError(InvalidSyntax, 1, 4)));
-}
-#[test]
-fn test_trailing_characters_streaming() {
-    assert_eq!(last_event("nulla"), Error(SyntaxError(TrailingCharacters, 1, 5)));
-    assert_eq!(last_event("truea"), Error(SyntaxError(TrailingCharacters, 1, 5)));
-    assert_eq!(last_event("falsea"), Error(SyntaxError(TrailingCharacters, 1, 6)));
-    assert_eq!(last_event("1a"), Error(SyntaxError(TrailingCharacters, 1, 2)));
-    assert_eq!(last_event("[]a"), Error(SyntaxError(TrailingCharacters, 1, 3)));
-    assert_eq!(last_event("{}a"), Error(SyntaxError(TrailingCharacters, 1, 3)));
-}
-#[test]
-fn test_read_identifiers_streaming() {
-    assert_eq!(Parser::new("null".chars()).next(), Some(NullValue));
-    assert_eq!(Parser::new("true".chars()).next(), Some(BooleanValue(true)));
-    assert_eq!(Parser::new("false".chars()).next(), Some(BooleanValue(false)));
-
-    assert_eq!(last_event("n"), Error(SyntaxError(InvalidSyntax, 1, 2)));
-    assert_eq!(last_event("nul"), Error(SyntaxError(InvalidSyntax, 1, 4)));
-    assert_eq!(last_event("t"), Error(SyntaxError(InvalidSyntax, 1, 2)));
-    assert_eq!(last_event("truz"), Error(SyntaxError(InvalidSyntax, 1, 4)));
-    assert_eq!(last_event("f"), Error(SyntaxError(InvalidSyntax, 1, 2)));
-    assert_eq!(last_event("faz"), Error(SyntaxError(InvalidSyntax, 1, 3)));
-}
-
-#[test]
-fn test_to_json() {
-    use json::ToJson;
-    use std::collections::{BTreeMap, HashMap};
-
-    let array2 = Array(vec![U64(1), U64(2)]);
-    let array3 = Array(vec![U64(1), U64(2), U64(3)]);
-    let object = {
-        let mut tree_map = BTreeMap::new();
-        tree_map.insert("a".to_string(), U64(1));
-        tree_map.insert("b".to_string(), U64(2));
-        Object(tree_map)
-    };
-
-    assert_eq!(array2.to_json(), array2);
-    assert_eq!(object.to_json(), object);
-    assert_eq!(3_isize.to_json(), I64(3));
-    assert_eq!(4_i8.to_json(), I64(4));
-    assert_eq!(5_i16.to_json(), I64(5));
-    assert_eq!(6_i32.to_json(), I64(6));
-    assert_eq!(7_i64.to_json(), I64(7));
-    assert_eq!(8_usize.to_json(), U64(8));
-    assert_eq!(9_u8.to_json(), U64(9));
-    assert_eq!(10_u16.to_json(), U64(10));
-    assert_eq!(11_u32.to_json(), U64(11));
-    assert_eq!(12_u64.to_json(), U64(12));
-    assert_eq!(13.0_f32.to_json(), F64(13.0_f64));
-    assert_eq!(14.0_f64.to_json(), F64(14.0_f64));
-    assert_eq!(().to_json(), Null);
-    assert_eq!(f32::INFINITY.to_json(), Null);
-    assert_eq!(f64::NAN.to_json(), Null);
-    assert_eq!(true.to_json(), Boolean(true));
-    assert_eq!(false.to_json(), Boolean(false));
-    assert_eq!("abc".to_json(), String("abc".to_string()));
-    assert_eq!("abc".to_string().to_json(), String("abc".to_string()));
-    assert_eq!((1_usize, 2_usize).to_json(), array2);
-    assert_eq!((1_usize, 2_usize, 3_usize).to_json(), array3);
-    assert_eq!([1_usize, 2_usize].to_json(), array2);
-    assert_eq!((&[1_usize, 2_usize, 3_usize]).to_json(), array3);
-    assert_eq!((vec![1_usize, 2_usize]).to_json(), array2);
-    assert_eq!(vec![1_usize, 2_usize, 3_usize].to_json(), array3);
-    let mut tree_map = BTreeMap::new();
-    tree_map.insert("a".to_string(), 1 as usize);
-    tree_map.insert("b".to_string(), 2);
-    assert_eq!(tree_map.to_json(), object);
-    let mut hash_map = HashMap::new();
-    hash_map.insert("a".to_string(), 1 as usize);
-    hash_map.insert("b".to_string(), 2);
-    assert_eq!(hash_map.to_json(), object);
-    assert_eq!(Some(15).to_json(), I64(15));
-    assert_eq!(Some(15 as usize).to_json(), U64(15));
-    assert_eq!(None::<isize>.to_json(), Null);
-}
-
-#[test]
-fn test_encode_hashmap_with_arbitrary_key() {
-    use std::collections::HashMap;
-    #[derive(PartialEq, Eq, Hash, Encodable)]
-    struct ArbitraryType(usize);
-    let mut hm: HashMap<ArbitraryType, bool> = HashMap::new();
-    hm.insert(ArbitraryType(1), true);
-    let mut mem_buf = string::String::new();
-    let mut encoder = Encoder::new(&mut mem_buf);
-    let result = hm.encode(&mut encoder);
-    match result.unwrap_err() {
-        EncoderError::BadHashmapKey => (),
-        _ => panic!("expected bad hash map key"),
-    }
-}
diff --git a/compiler/rustc_serialize/tests/opaque.rs b/compiler/rustc_serialize/tests/opaque.rs
index 298eb11..3a695d0 100644
--- a/compiler/rustc_serialize/tests/opaque.rs
+++ b/compiler/rustc_serialize/tests/opaque.rs
@@ -1,7 +1,7 @@
 #![allow(rustc::internal)]
 
 use rustc_macros::{Decodable, Encodable};
-use rustc_serialize::opaque::{Decoder, Encoder};
+use rustc_serialize::opaque::{MemDecoder, MemEncoder};
 use rustc_serialize::{Decodable, Encodable};
 use std::fmt::Debug;
 
@@ -28,17 +28,18 @@
     q: Option<u32>,
 }
 
-fn check_round_trip<T: Encodable<Encoder> + for<'a> Decodable<Decoder<'a>> + PartialEq + Debug>(
+fn check_round_trip<
+    T: Encodable<MemEncoder> + for<'a> Decodable<MemDecoder<'a>> + PartialEq + Debug,
+>(
     values: Vec<T>,
 ) {
-    let mut encoder = Encoder::new(Vec::new());
-
+    let mut encoder = MemEncoder::new();
     for value in &values {
-        Encodable::encode(value, &mut encoder).unwrap();
+        Encodable::encode(value, &mut encoder);
     }
 
-    let data = encoder.into_inner();
-    let mut decoder = Decoder::new(&data[..], 0);
+    let data = encoder.finish();
+    let mut decoder = MemDecoder::new(&data[..], 0);
 
     for value in values {
         let decoded = Decodable::decode(&mut decoder);
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index 530c1a0..14ad1a4 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -547,23 +547,6 @@
     LinkArgs,
 }
 
-#[derive(Copy, Clone)]
-pub enum BorrowckMode {
-    Mir,
-    Migrate,
-}
-
-impl BorrowckMode {
-    /// Returns whether we should run the MIR-based borrow check, but also fall back
-    /// on the AST borrow check if the MIR-based one errors.
-    pub fn migrate(self) -> bool {
-        match self {
-            BorrowckMode::Mir => false,
-            BorrowckMode::Migrate => true,
-        }
-    }
-}
-
 pub enum Input {
     /// Load source code from a file.
     File(PathBuf),
@@ -741,7 +724,6 @@
             incremental: None,
             debugging_opts: Default::default(),
             prints: Vec::new(),
-            borrowck_mode: BorrowckMode::Migrate,
             cg: Default::default(),
             error_format: ErrorOutputType::default(),
             externs: Externs(BTreeMap::new()),
@@ -1120,41 +1102,96 @@
             .extend(atomic_values);
 
         // Target specific values
-        for target in
-            TARGETS.iter().map(|target| Target::expect_builtin(&TargetTriple::from_triple(target)))
+        #[cfg(bootstrap)]
         {
-            self.values_valid
-                .entry(sym::target_os)
-                .or_default()
-                .insert(Symbol::intern(&target.options.os));
-            self.values_valid
-                .entry(sym::target_family)
-                .or_default()
-                .extend(target.options.families.iter().map(|family| Symbol::intern(family)));
-            self.values_valid
-                .entry(sym::target_arch)
-                .or_default()
-                .insert(Symbol::intern(&target.arch));
-            self.values_valid
-                .entry(sym::target_endian)
-                .or_default()
-                .insert(Symbol::intern(&target.options.endian.as_str()));
-            self.values_valid
-                .entry(sym::target_env)
-                .or_default()
-                .insert(Symbol::intern(&target.options.env));
-            self.values_valid
-                .entry(sym::target_abi)
-                .or_default()
-                .insert(Symbol::intern(&target.options.abi));
-            self.values_valid
-                .entry(sym::target_vendor)
-                .or_default()
-                .insert(Symbol::intern(&target.options.vendor));
-            self.values_valid
-                .entry(sym::target_pointer_width)
-                .or_default()
-                .insert(sym::integer(target.pointer_width));
+            for target in TARGETS
+                .iter()
+                .map(|target| Target::expect_builtin(&TargetTriple::from_triple(target)))
+            {
+                self.values_valid
+                    .entry(sym::target_os)
+                    .or_default()
+                    .insert(Symbol::intern(&target.options.os));
+                self.values_valid
+                    .entry(sym::target_family)
+                    .or_default()
+                    .extend(target.options.families.iter().map(|family| Symbol::intern(family)));
+                self.values_valid
+                    .entry(sym::target_arch)
+                    .or_default()
+                    .insert(Symbol::intern(&target.arch));
+                self.values_valid
+                    .entry(sym::target_endian)
+                    .or_default()
+                    .insert(Symbol::intern(&target.options.endian.as_str()));
+                self.values_valid
+                    .entry(sym::target_env)
+                    .or_default()
+                    .insert(Symbol::intern(&target.options.env));
+                self.values_valid
+                    .entry(sym::target_abi)
+                    .or_default()
+                    .insert(Symbol::intern(&target.options.abi));
+                self.values_valid
+                    .entry(sym::target_vendor)
+                    .or_default()
+                    .insert(Symbol::intern(&target.options.vendor));
+                self.values_valid
+                    .entry(sym::target_pointer_width)
+                    .or_default()
+                    .insert(sym::integer(target.pointer_width));
+            }
+        }
+
+        // Target specific values
+        #[cfg(not(bootstrap))]
+        {
+            const VALUES: [&Symbol; 8] = [
+                &sym::target_os,
+                &sym::target_family,
+                &sym::target_arch,
+                &sym::target_endian,
+                &sym::target_env,
+                &sym::target_abi,
+                &sym::target_vendor,
+                &sym::target_pointer_width,
+            ];
+
+            // Initialize (if not already initialized)
+            for &e in VALUES {
+                self.values_valid.entry(e).or_default();
+            }
+
+            // Get all values map at once otherwise it would be costly.
+            // (8 values * 220 targets ~= 1760 times, at the time of writing this comment).
+            let [
+                values_target_os,
+                values_target_family,
+                values_target_arch,
+                values_target_endian,
+                values_target_env,
+                values_target_abi,
+                values_target_vendor,
+                values_target_pointer_width,
+            ] = self
+                .values_valid
+                .get_many_mut(VALUES)
+                .expect("unable to get all the check-cfg values buckets");
+
+            for target in TARGETS
+                .iter()
+                .map(|target| Target::expect_builtin(&TargetTriple::from_triple(target)))
+            {
+                values_target_os.insert(Symbol::intern(&target.options.os));
+                values_target_family
+                    .extend(target.options.families.iter().map(|family| Symbol::intern(family)));
+                values_target_arch.insert(Symbol::intern(&target.arch));
+                values_target_endian.insert(Symbol::intern(&target.options.endian.as_str()));
+                values_target_env.insert(Symbol::intern(&target.options.env));
+                values_target_abi.insert(Symbol::intern(&target.options.abi));
+                values_target_vendor.insert(Symbol::intern(&target.options.vendor));
+                values_target_pointer_width.insert(sym::integer(target.pointer_width));
+            }
         }
     }
 
@@ -1450,7 +1487,7 @@
     let mut lint_opts_with_position = vec![];
     let mut describe_lints = false;
 
-    for level in [lint::Allow, lint::Warn, lint::ForceWarn, lint::Deny, lint::Forbid] {
+    for level in [lint::Allow, lint::Warn, lint::ForceWarn(None), lint::Deny, lint::Forbid] {
         for (arg_pos, lint_name) in matches.opt_strs_pos(level.as_str()) {
             if lint_name == "help" {
                 describe_lints = true;
@@ -1912,7 +1949,7 @@
     }
 }
 
-crate fn parse_assert_incr_state(
+pub(crate) fn parse_assert_incr_state(
     opt_assertion: &Option<String>,
     error_format: ErrorOutputType,
 ) -> Option<IncrementalStateAssertion> {
@@ -1937,33 +1974,12 @@
     };
 
     let kind = match kind {
+        "static" => NativeLibKind::Static { bundle: None, whole_archive: None },
         "dylib" => NativeLibKind::Dylib { as_needed: None },
         "framework" => NativeLibKind::Framework { as_needed: None },
-        "static" => NativeLibKind::Static { bundle: None, whole_archive: None },
-        "static-nobundle" => {
-            early_warn(
-                error_format,
-                "library kind `static-nobundle` has been superseded by specifying \
-                `-bundle` on library kind `static`. Try `static:-bundle`",
-            );
-            if modifiers.is_some() {
-                early_error(
-                    error_format,
-                    "linking modifier can't be used with library kind `static-nobundle`",
-                )
-            }
-            if !nightly_options::match_is_nightly_build(matches) {
-                early_error(
-                    error_format,
-                    "library kind `static-nobundle` are currently unstable and only accepted on \
-                the nightly compiler",
-                );
-            }
-            NativeLibKind::Static { bundle: Some(false), whole_archive: None }
-        }
-        s => early_error(
+        _ => early_error(
             error_format,
-            &format!("unknown library kind `{s}`, expected one of dylib, framework, or static"),
+            &format!("unknown library kind `{kind}`, expected one of: static, dylib, framework"),
         ),
     };
     match modifiers {
@@ -1978,21 +1994,6 @@
     error_format: ErrorOutputType,
     matches: &getopts::Matches,
 ) -> (NativeLibKind, Option<bool>) {
-    let report_unstable_modifier = |modifier| {
-        if !nightly_options::is_unstable_enabled(matches) {
-            let why = if nightly_options::match_is_nightly_build(matches) {
-                " and only accepted on the nightly compiler"
-            } else {
-                ", the `-Z unstable-options` flag must also be passed to use it"
-            };
-            early_error(
-                error_format,
-                &format!("{modifier} linking modifier is currently unstable{why}"),
-            )
-        }
-    };
-
-    let mut has_duplicate_modifiers = false;
     let mut verbatim = None;
     for modifier in modifiers.split(',') {
         let (modifier, value) = match modifier.strip_prefix(&['+', '-']) {
@@ -2000,56 +2001,60 @@
             None => early_error(
                 error_format,
                 "invalid linking modifier syntax, expected '+' or '-' prefix \
-                    before one of: bundle, verbatim, whole-archive, as-needed",
+                 before one of: bundle, verbatim, whole-archive, as-needed",
             ),
         };
 
-        match (modifier, &mut kind) {
-            ("bundle", NativeLibKind::Static { bundle, .. }) => {
-                report_unstable_modifier(modifier);
-                if bundle.is_some() {
-                    has_duplicate_modifiers = true;
-                }
-                *bundle = Some(value);
+        let report_unstable_modifier = || {
+            if !nightly_options::is_unstable_enabled(matches) {
+                let why = if nightly_options::match_is_nightly_build(matches) {
+                    " and only accepted on the nightly compiler"
+                } else {
+                    ", the `-Z unstable-options` flag must also be passed to use it"
+                };
+                early_error(
+                    error_format,
+                    &format!("linking modifier `{modifier}` is unstable{why}"),
+                )
             }
+        };
+        let assign_modifier = |dst: &mut Option<bool>| {
+            if dst.is_some() {
+                let msg = format!("multiple `{modifier}` modifiers in a single `-l` option");
+                early_error(error_format, &msg)
+            } else {
+                *dst = Some(value);
+            }
+        };
+        match (modifier, &mut kind) {
+            ("bundle", NativeLibKind::Static { bundle, .. }) => assign_modifier(bundle),
             ("bundle", _) => early_error(
                 error_format,
-                "bundle linking modifier is only compatible with \
-                    `static` linking kind",
+                "linking modifier `bundle` is only compatible with `static` linking kind",
             ),
 
             ("verbatim", _) => {
-                report_unstable_modifier(modifier);
-                if verbatim.is_some() {
-                    has_duplicate_modifiers = true;
-                }
-                verbatim = Some(value);
+                report_unstable_modifier();
+                assign_modifier(&mut verbatim)
             }
 
             ("whole-archive", NativeLibKind::Static { whole_archive, .. }) => {
-                if whole_archive.is_some() {
-                    has_duplicate_modifiers = true;
-                }
-                *whole_archive = Some(value);
+                assign_modifier(whole_archive)
             }
             ("whole-archive", _) => early_error(
                 error_format,
-                "whole-archive linking modifier is only compatible with \
-                    `static` linking kind",
+                "linking modifier `whole-archive` is only compatible with `static` linking kind",
             ),
 
             ("as-needed", NativeLibKind::Dylib { as_needed })
             | ("as-needed", NativeLibKind::Framework { as_needed }) => {
-                report_unstable_modifier(modifier);
-                if as_needed.is_some() {
-                    has_duplicate_modifiers = true;
-                }
-                *as_needed = Some(value);
+                report_unstable_modifier();
+                assign_modifier(as_needed)
             }
             ("as-needed", _) => early_error(
                 error_format,
-                "as-needed linking modifier is only compatible with \
-                    `dylib` and `framework` linking kinds",
+                "linking modifier `as-needed` is only compatible with \
+                 `dylib` and `framework` linking kinds",
             ),
 
             // Note: this error also excludes the case with empty modifier
@@ -2057,15 +2062,12 @@
             _ => early_error(
                 error_format,
                 &format!(
-                    "unrecognized linking modifier `{modifier}`, expected one \
-                    of: bundle, verbatim, whole-archive, as-needed"
+                    "unknown linking modifier `{modifier}`, expected one \
+                     of: bundle, verbatim, whole-archive, as-needed"
                 ),
             ),
         }
     }
-    if has_duplicate_modifiers {
-        report_unstable_modifier("duplicating")
-    }
 
     (kind, verbatim)
 }
@@ -2093,19 +2095,14 @@
                 None => (name, None),
                 Some((name, new_name)) => (name.to_string(), Some(new_name.to_owned())),
             };
+            if name.is_empty() {
+                early_error(error_format, "library name must not be empty");
+            }
             NativeLib { name, new_name, kind, verbatim }
         })
         .collect()
 }
 
-fn parse_borrowck_mode(dopts: &DebuggingOptions, error_format: ErrorOutputType) -> BorrowckMode {
-    match dopts.borrowck.as_ref() {
-        "migrate" => BorrowckMode::Migrate,
-        "mir" => BorrowckMode::Mir,
-        m => early_error(error_format, &format!("unknown borrowck mode `{m}`")),
-    }
-}
-
 pub fn parse_externs(
     matches: &getopts::Matches,
     debugging_opts: &DebuggingOptions,
@@ -2443,8 +2440,6 @@
 
     let test = matches.opt_present("test");
 
-    let borrowck_mode = parse_borrowck_mode(&debugging_opts, error_format);
-
     if !cg.remark.is_empty() && debuginfo == DebugInfo::None {
         early_warn(error_format, "-C remark requires \"-C debuginfo=n\" to show source locations");
     }
@@ -2520,7 +2515,6 @@
         incremental,
         debugging_opts,
         prints,
-        borrowck_mode,
         cg,
         error_format,
         externs,
@@ -2769,7 +2763,7 @@
 /// `Hash` implementation for `DepTrackingHash`. It's important though that
 /// we have an opt-in scheme here, so one is hopefully forced to think about
 /// how the hash should be calculated when adding a new command-line argument.
-crate mod dep_tracking {
+pub(crate) mod dep_tracking {
     use super::{
         BranchProtection, CFGuard, CFProtection, CrateType, DebugInfo, ErrorOutputType,
         InstrumentCoverage, LdImpl, LinkerPluginLto, LocationDetail, LtoCli, OomStrategy, OptLevel,
@@ -2947,7 +2941,7 @@
     }
 
     // This is a stable hash because BTreeMap is a sorted container
-    crate fn stable_hash(
+    pub(crate) fn stable_hash(
         sub_hashes: BTreeMap<&'static str, &dyn DepTrackingHash>,
         hasher: &mut DefaultHasher,
         error_format: ErrorOutputType,
diff --git a/compiler/rustc_session/src/lib.rs b/compiler/rustc_session/src/lib.rs
index 054b18b..35b5598 100644
--- a/compiler/rustc_session/src/lib.rs
+++ b/compiler/rustc_session/src/lib.rs
@@ -1,12 +1,12 @@
-#![feature(crate_visibility_modifier)]
 #![feature(if_let_guard)]
 #![feature(let_chains)]
-#![cfg_attr(bootstrap, feature(derive_default_enum))]
 #![feature(let_else)]
 #![feature(min_specialization)]
 #![feature(never_type)]
 #![feature(once_cell)]
 #![feature(option_get_or_insert_default)]
+#![feature(rustc_attrs)]
+#![cfg_attr(not(bootstrap), feature(map_many_mut))]
 #![recursion_limit = "256"]
 #![allow(rustc::potential_query_instability)]
 
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index 5c404b6..441e1f9 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -178,9 +178,6 @@
 
         debugging_opts: DebuggingOptions [SUBSTRUCT],
         prints: Vec<PrintRequest> [UNTRACKED],
-        /// Determines which borrow checker(s) to run. This is the parsed, sanitized
-        /// version of `debugging_opts.borrowck`, which is just a plain string.
-        borrowck_mode: BorrowckMode [UNTRACKED],
         cg: CodegenOptions [SUBSTRUCT],
         externs: Externs [UNTRACKED],
         crate_name: Option<String> [TRACKED],
@@ -421,12 +418,12 @@
 }
 
 mod parse {
-    crate use super::*;
+    pub(crate) use super::*;
     use std::str::FromStr;
 
     /// This is for boolean options that don't take a value and start with
     /// `no-`. This style of option is deprecated.
-    crate fn parse_no_flag(slot: &mut bool, v: Option<&str>) -> bool {
+    pub(crate) fn parse_no_flag(slot: &mut bool, v: Option<&str>) -> bool {
         match v {
             None => {
                 *slot = true;
@@ -437,7 +434,7 @@
     }
 
     /// Use this for any boolean option that has a static default.
-    crate fn parse_bool(slot: &mut bool, v: Option<&str>) -> bool {
+    pub(crate) fn parse_bool(slot: &mut bool, v: Option<&str>) -> bool {
         match v {
             Some("y") | Some("yes") | Some("on") | None => {
                 *slot = true;
@@ -454,7 +451,7 @@
     /// Use this for any boolean option that lacks a static default. (The
     /// actions taken when such an option is not specified will depend on
     /// other factors, such as other options, or target options.)
-    crate fn parse_opt_bool(slot: &mut Option<bool>, v: Option<&str>) -> bool {
+    pub(crate) fn parse_opt_bool(slot: &mut Option<bool>, v: Option<&str>) -> bool {
         match v {
             Some("y") | Some("yes") | Some("on") | None => {
                 *slot = Some(true);
@@ -469,7 +466,7 @@
     }
 
     /// Use this for any string option that has a static default.
-    crate fn parse_string(slot: &mut String, v: Option<&str>) -> bool {
+    pub(crate) fn parse_string(slot: &mut String, v: Option<&str>) -> bool {
         match v {
             Some(s) => {
                 *slot = s.to_string();
@@ -480,7 +477,7 @@
     }
 
     /// Use this for any string option that lacks a static default.
-    crate fn parse_opt_string(slot: &mut Option<String>, v: Option<&str>) -> bool {
+    pub(crate) fn parse_opt_string(slot: &mut Option<String>, v: Option<&str>) -> bool {
         match v {
             Some(s) => {
                 *slot = Some(s.to_string());
@@ -491,7 +488,7 @@
     }
 
     /// Parse an optional language identifier, e.g. `en-US` or `zh-CN`.
-    crate fn parse_opt_langid(slot: &mut Option<LanguageIdentifier>, v: Option<&str>) -> bool {
+    pub(crate) fn parse_opt_langid(slot: &mut Option<LanguageIdentifier>, v: Option<&str>) -> bool {
         match v {
             Some(s) => {
                 *slot = rustc_errors::LanguageIdentifier::from_str(s).ok();
@@ -501,7 +498,7 @@
         }
     }
 
-    crate fn parse_opt_pathbuf(slot: &mut Option<PathBuf>, v: Option<&str>) -> bool {
+    pub(crate) fn parse_opt_pathbuf(slot: &mut Option<PathBuf>, v: Option<&str>) -> bool {
         match v {
             Some(s) => {
                 *slot = Some(PathBuf::from(s));
@@ -511,7 +508,7 @@
         }
     }
 
-    crate fn parse_string_push(slot: &mut Vec<String>, v: Option<&str>) -> bool {
+    pub(crate) fn parse_string_push(slot: &mut Vec<String>, v: Option<&str>) -> bool {
         match v {
             Some(s) => {
                 slot.push(s.to_string());
@@ -521,7 +518,7 @@
         }
     }
 
-    crate fn parse_list(slot: &mut Vec<String>, v: Option<&str>) -> bool {
+    pub(crate) fn parse_list(slot: &mut Vec<String>, v: Option<&str>) -> bool {
         match v {
             Some(s) => {
                 slot.extend(s.split_whitespace().map(|s| s.to_string()));
@@ -531,7 +528,10 @@
         }
     }
 
-    crate fn parse_list_with_polarity(slot: &mut Vec<(String, bool)>, v: Option<&str>) -> bool {
+    pub(crate) fn parse_list_with_polarity(
+        slot: &mut Vec<(String, bool)>,
+        v: Option<&str>,
+    ) -> bool {
         match v {
             Some(s) => {
                 for s in s.split(",") {
@@ -544,7 +544,7 @@
         }
     }
 
-    crate fn parse_location_detail(ld: &mut LocationDetail, v: Option<&str>) -> bool {
+    pub(crate) fn parse_location_detail(ld: &mut LocationDetail, v: Option<&str>) -> bool {
         if let Some(v) = v {
             ld.line = false;
             ld.file = false;
@@ -563,7 +563,7 @@
         }
     }
 
-    crate fn parse_opt_comma_list(slot: &mut Option<Vec<String>>, v: Option<&str>) -> bool {
+    pub(crate) fn parse_opt_comma_list(slot: &mut Option<Vec<String>>, v: Option<&str>) -> bool {
         match v {
             Some(s) => {
                 let mut v: Vec<_> = s.split(',').map(|s| s.to_string()).collect();
@@ -575,7 +575,7 @@
         }
     }
 
-    crate fn parse_threads(slot: &mut usize, v: Option<&str>) -> bool {
+    pub(crate) fn parse_threads(slot: &mut usize, v: Option<&str>) -> bool {
         match v.and_then(|s| s.parse().ok()) {
             Some(0) => {
                 *slot = ::num_cpus::get();
@@ -590,7 +590,7 @@
     }
 
     /// Use this for any numeric option that has a static default.
-    crate fn parse_number<T: Copy + FromStr>(slot: &mut T, v: Option<&str>) -> bool {
+    pub(crate) fn parse_number<T: Copy + FromStr>(slot: &mut T, v: Option<&str>) -> bool {
         match v.and_then(|s| s.parse().ok()) {
             Some(i) => {
                 *slot = i;
@@ -601,7 +601,10 @@
     }
 
     /// Use this for any numeric option that lacks a static default.
-    crate fn parse_opt_number<T: Copy + FromStr>(slot: &mut Option<T>, v: Option<&str>) -> bool {
+    pub(crate) fn parse_opt_number<T: Copy + FromStr>(
+        slot: &mut Option<T>,
+        v: Option<&str>,
+    ) -> bool {
         match v {
             Some(s) => {
                 *slot = s.parse().ok();
@@ -611,7 +614,7 @@
         }
     }
 
-    crate fn parse_passes(slot: &mut Passes, v: Option<&str>) -> bool {
+    pub(crate) fn parse_passes(slot: &mut Passes, v: Option<&str>) -> bool {
         match v {
             Some("all") => {
                 *slot = Passes::All;
@@ -629,7 +632,10 @@
         }
     }
 
-    crate fn parse_opt_panic_strategy(slot: &mut Option<PanicStrategy>, v: Option<&str>) -> bool {
+    pub(crate) fn parse_opt_panic_strategy(
+        slot: &mut Option<PanicStrategy>,
+        v: Option<&str>,
+    ) -> bool {
         match v {
             Some("unwind") => *slot = Some(PanicStrategy::Unwind),
             Some("abort") => *slot = Some(PanicStrategy::Abort),
@@ -638,7 +644,7 @@
         true
     }
 
-    crate fn parse_panic_strategy(slot: &mut PanicStrategy, v: Option<&str>) -> bool {
+    pub(crate) fn parse_panic_strategy(slot: &mut PanicStrategy, v: Option<&str>) -> bool {
         match v {
             Some("unwind") => *slot = PanicStrategy::Unwind,
             Some("abort") => *slot = PanicStrategy::Abort,
@@ -647,7 +653,7 @@
         true
     }
 
-    crate fn parse_oom_strategy(slot: &mut OomStrategy, v: Option<&str>) -> bool {
+    pub(crate) fn parse_oom_strategy(slot: &mut OomStrategy, v: Option<&str>) -> bool {
         match v {
             Some("panic") => *slot = OomStrategy::Panic,
             Some("abort") => *slot = OomStrategy::Abort,
@@ -656,7 +662,7 @@
         true
     }
 
-    crate fn parse_relro_level(slot: &mut Option<RelroLevel>, v: Option<&str>) -> bool {
+    pub(crate) fn parse_relro_level(slot: &mut Option<RelroLevel>, v: Option<&str>) -> bool {
         match v {
             Some(s) => match s.parse::<RelroLevel>() {
                 Ok(level) => *slot = Some(level),
@@ -667,7 +673,7 @@
         true
     }
 
-    crate fn parse_sanitizers(slot: &mut SanitizerSet, v: Option<&str>) -> bool {
+    pub(crate) fn parse_sanitizers(slot: &mut SanitizerSet, v: Option<&str>) -> bool {
         if let Some(v) = v {
             for s in v.split(',') {
                 *slot |= match s {
@@ -687,7 +693,7 @@
         }
     }
 
-    crate fn parse_sanitizer_memory_track_origins(slot: &mut usize, v: Option<&str>) -> bool {
+    pub(crate) fn parse_sanitizer_memory_track_origins(slot: &mut usize, v: Option<&str>) -> bool {
         match v {
             Some("2") | None => {
                 *slot = 2;
@@ -705,7 +711,7 @@
         }
     }
 
-    crate fn parse_strip(slot: &mut Strip, v: Option<&str>) -> bool {
+    pub(crate) fn parse_strip(slot: &mut Strip, v: Option<&str>) -> bool {
         match v {
             Some("none") => *slot = Strip::None,
             Some("debuginfo") => *slot = Strip::Debuginfo,
@@ -715,7 +721,7 @@
         true
     }
 
-    crate fn parse_cfguard(slot: &mut CFGuard, v: Option<&str>) -> bool {
+    pub(crate) fn parse_cfguard(slot: &mut CFGuard, v: Option<&str>) -> bool {
         if v.is_some() {
             let mut bool_arg = None;
             if parse_opt_bool(&mut bool_arg, v) {
@@ -733,7 +739,7 @@
         true
     }
 
-    crate fn parse_cfprotection(slot: &mut CFProtection, v: Option<&str>) -> bool {
+    pub(crate) fn parse_cfprotection(slot: &mut CFProtection, v: Option<&str>) -> bool {
         if v.is_some() {
             let mut bool_arg = None;
             if parse_opt_bool(&mut bool_arg, v) {
@@ -752,7 +758,7 @@
         true
     }
 
-    crate fn parse_linker_flavor(slot: &mut Option<LinkerFlavor>, v: Option<&str>) -> bool {
+    pub(crate) fn parse_linker_flavor(slot: &mut Option<LinkerFlavor>, v: Option<&str>) -> bool {
         match v.and_then(LinkerFlavor::from_str) {
             Some(lf) => *slot = Some(lf),
             _ => return false,
@@ -760,7 +766,10 @@
         true
     }
 
-    crate fn parse_optimization_fuel(slot: &mut Option<(String, u64)>, v: Option<&str>) -> bool {
+    pub(crate) fn parse_optimization_fuel(
+        slot: &mut Option<(String, u64)>,
+        v: Option<&str>,
+    ) -> bool {
         match v {
             None => false,
             Some(s) => {
@@ -779,7 +788,7 @@
         }
     }
 
-    crate fn parse_unpretty(slot: &mut Option<String>, v: Option<&str>) -> bool {
+    pub(crate) fn parse_unpretty(slot: &mut Option<String>, v: Option<&str>) -> bool {
         match v {
             None => false,
             Some(s) if s.split('=').count() <= 2 => {
@@ -790,7 +799,7 @@
         }
     }
 
-    crate fn parse_mir_spanview(slot: &mut Option<MirSpanview>, v: Option<&str>) -> bool {
+    pub(crate) fn parse_mir_spanview(slot: &mut Option<MirSpanview>, v: Option<&str>) -> bool {
         if v.is_some() {
             let mut bool_arg = None;
             if parse_opt_bool(&mut bool_arg, v) {
@@ -813,7 +822,7 @@
         true
     }
 
-    crate fn parse_instrument_coverage(
+    pub(crate) fn parse_instrument_coverage(
         slot: &mut Option<InstrumentCoverage>,
         v: Option<&str>,
     ) -> bool {
@@ -844,7 +853,7 @@
         true
     }
 
-    crate fn parse_treat_err_as_bug(slot: &mut Option<NonZeroUsize>, v: Option<&str>) -> bool {
+    pub(crate) fn parse_treat_err_as_bug(slot: &mut Option<NonZeroUsize>, v: Option<&str>) -> bool {
         match v {
             Some(s) => {
                 *slot = s.parse().ok();
@@ -857,7 +866,7 @@
         }
     }
 
-    crate fn parse_lto(slot: &mut LtoCli, v: Option<&str>) -> bool {
+    pub(crate) fn parse_lto(slot: &mut LtoCli, v: Option<&str>) -> bool {
         if v.is_some() {
             let mut bool_arg = None;
             if parse_opt_bool(&mut bool_arg, v) {
@@ -875,7 +884,7 @@
         true
     }
 
-    crate fn parse_linker_plugin_lto(slot: &mut LinkerPluginLto, v: Option<&str>) -> bool {
+    pub(crate) fn parse_linker_plugin_lto(slot: &mut LinkerPluginLto, v: Option<&str>) -> bool {
         if v.is_some() {
             let mut bool_arg = None;
             if parse_opt_bool(&mut bool_arg, v) {
@@ -895,7 +904,10 @@
         true
     }
 
-    crate fn parse_switch_with_opt_path(slot: &mut SwitchWithOptPath, v: Option<&str>) -> bool {
+    pub(crate) fn parse_switch_with_opt_path(
+        slot: &mut SwitchWithOptPath,
+        v: Option<&str>,
+    ) -> bool {
         *slot = match v {
             None => SwitchWithOptPath::Enabled(None),
             Some(path) => SwitchWithOptPath::Enabled(Some(PathBuf::from(path))),
@@ -903,7 +915,10 @@
         true
     }
 
-    crate fn parse_merge_functions(slot: &mut Option<MergeFunctions>, v: Option<&str>) -> bool {
+    pub(crate) fn parse_merge_functions(
+        slot: &mut Option<MergeFunctions>,
+        v: Option<&str>,
+    ) -> bool {
         match v.and_then(|s| MergeFunctions::from_str(s).ok()) {
             Some(mergefunc) => *slot = Some(mergefunc),
             _ => return false,
@@ -911,7 +926,7 @@
         true
     }
 
-    crate fn parse_relocation_model(slot: &mut Option<RelocModel>, v: Option<&str>) -> bool {
+    pub(crate) fn parse_relocation_model(slot: &mut Option<RelocModel>, v: Option<&str>) -> bool {
         match v.and_then(|s| RelocModel::from_str(s).ok()) {
             Some(relocation_model) => *slot = Some(relocation_model),
             None if v == Some("default") => *slot = None,
@@ -920,7 +935,7 @@
         true
     }
 
-    crate fn parse_code_model(slot: &mut Option<CodeModel>, v: Option<&str>) -> bool {
+    pub(crate) fn parse_code_model(slot: &mut Option<CodeModel>, v: Option<&str>) -> bool {
         match v.and_then(|s| CodeModel::from_str(s).ok()) {
             Some(code_model) => *slot = Some(code_model),
             _ => return false,
@@ -928,7 +943,7 @@
         true
     }
 
-    crate fn parse_tls_model(slot: &mut Option<TlsModel>, v: Option<&str>) -> bool {
+    pub(crate) fn parse_tls_model(slot: &mut Option<TlsModel>, v: Option<&str>) -> bool {
         match v.and_then(|s| TlsModel::from_str(s).ok()) {
             Some(tls_model) => *slot = Some(tls_model),
             _ => return false,
@@ -936,7 +951,7 @@
         true
     }
 
-    crate fn parse_symbol_mangling_version(
+    pub(crate) fn parse_symbol_mangling_version(
         slot: &mut Option<SymbolManglingVersion>,
         v: Option<&str>,
     ) -> bool {
@@ -948,7 +963,7 @@
         true
     }
 
-    crate fn parse_src_file_hash(
+    pub(crate) fn parse_src_file_hash(
         slot: &mut Option<SourceFileHashAlgorithm>,
         v: Option<&str>,
     ) -> bool {
@@ -959,7 +974,7 @@
         true
     }
 
-    crate fn parse_target_feature(slot: &mut String, v: Option<&str>) -> bool {
+    pub(crate) fn parse_target_feature(slot: &mut String, v: Option<&str>) -> bool {
         match v {
             Some(s) => {
                 if !slot.is_empty() {
@@ -972,7 +987,7 @@
         }
     }
 
-    crate fn parse_wasi_exec_model(slot: &mut Option<WasiExecModel>, v: Option<&str>) -> bool {
+    pub(crate) fn parse_wasi_exec_model(slot: &mut Option<WasiExecModel>, v: Option<&str>) -> bool {
         match v {
             Some("command") => *slot = Some(WasiExecModel::Command),
             Some("reactor") => *slot = Some(WasiExecModel::Reactor),
@@ -981,7 +996,10 @@
         true
     }
 
-    crate fn parse_split_debuginfo(slot: &mut Option<SplitDebuginfo>, v: Option<&str>) -> bool {
+    pub(crate) fn parse_split_debuginfo(
+        slot: &mut Option<SplitDebuginfo>,
+        v: Option<&str>,
+    ) -> bool {
         match v.and_then(|s| SplitDebuginfo::from_str(s).ok()) {
             Some(e) => *slot = Some(e),
             _ => return false,
@@ -989,7 +1007,7 @@
         true
     }
 
-    crate fn parse_split_dwarf_kind(slot: &mut SplitDwarfKind, v: Option<&str>) -> bool {
+    pub(crate) fn parse_split_dwarf_kind(slot: &mut SplitDwarfKind, v: Option<&str>) -> bool {
         match v.and_then(|s| SplitDwarfKind::from_str(s).ok()) {
             Some(e) => *slot = e,
             _ => return false,
@@ -997,7 +1015,7 @@
         true
     }
 
-    crate fn parse_gcc_ld(slot: &mut Option<LdImpl>, v: Option<&str>) -> bool {
+    pub(crate) fn parse_gcc_ld(slot: &mut Option<LdImpl>, v: Option<&str>) -> bool {
         match v {
             None => *slot = None,
             Some("lld") => *slot = Some(LdImpl::Lld),
@@ -1006,7 +1024,7 @@
         true
     }
 
-    crate fn parse_stack_protector(slot: &mut StackProtector, v: Option<&str>) -> bool {
+    pub(crate) fn parse_stack_protector(slot: &mut StackProtector, v: Option<&str>) -> bool {
         match v.and_then(|s| StackProtector::from_str(s).ok()) {
             Some(ssp) => *slot = ssp,
             _ => return false,
@@ -1014,7 +1032,10 @@
         true
     }
 
-    crate fn parse_branch_protection(slot: &mut Option<BranchProtection>, v: Option<&str>) -> bool {
+    pub(crate) fn parse_branch_protection(
+        slot: &mut Option<BranchProtection>,
+        v: Option<&str>,
+    ) -> bool {
         match v {
             Some(s) => {
                 let slot = slot.get_or_insert_default();
@@ -1183,15 +1204,9 @@
     assert_incr_state: Option<String> = (None, parse_opt_string, [UNTRACKED],
         "assert that the incremental cache is in given state: \
          either `loaded` or `not-loaded`."),
-    ast_json: bool = (false, parse_bool, [UNTRACKED],
-        "print the AST as JSON and halt (default: no)"),
-    ast_json_noexpand: bool = (false, parse_bool, [UNTRACKED],
-        "print the pre-expansion AST as JSON and halt (default: no)"),
     binary_dep_depinfo: bool = (false, parse_bool, [TRACKED],
         "include artifacts (sysroot, crate dependencies) used during compilation in dep-info \
         (default: no)"),
-    borrowck: String = ("migrate".to_string(), parse_string, [UNTRACKED],
-        "select which borrowck is used (`mir` or `migrate`) (default: `migrate`)"),
     branch_protection: Option<BranchProtection> = (None, parse_branch_protection, [TRACKED],
         "set options for branch target identification and pointer authentication on AArch64"),
     cf_protection: CFProtection = (CFProtection::None, parse_cfprotection, [TRACKED],
@@ -1458,6 +1473,12 @@
         for example: `-Z self-profile-events=default,query-keys`
         all options: none, all, default, generic-activity, query-provider, query-cache-hit
                      query-blocked, incr-cache-load, incr-result-hashing, query-keys, function-args, args, llvm, artifact-sizes"),
+    self_profile_counter: String = ("wall-time".to_string(), parse_string, [UNTRACKED],
+        "counter used by the self profiler (default: `wall-time`), one of:
+        `wall-time` (monotonic clock, i.e. `std::time::Instant`)
+        `instructions:u` (retired instructions, userspace-only)
+        `instructions-minus-irqs:u` (subtracting hardware interrupt counts for extra accuracy)"
+    ),
     share_generics: Option<bool> = (None, parse_opt_bool, [TRACKED],
         "make the current crate share its generic instantiations"),
     show_span: Option<String> = (None, parse_opt_string, [TRACKED],
@@ -1471,6 +1492,8 @@
         "hash algorithm of source files in debug info (`md5`, `sha1`, or `sha256`)"),
     stack_protector: StackProtector = (StackProtector::None, parse_stack_protector, [TRACKED],
         "control stack smash protection strategy (`rustc --print stack-protector-strategies` for details)"),
+    strict_init_checks: bool = (false, parse_bool, [TRACKED],
+        "control if mem::uninitialized and mem::zeroed panic on more UB"),
     strip: Strip = (Strip::None, parse_strip, [UNTRACKED],
         "tell the linker which information to strip (`none` (default), `debuginfo` or `symbols`)"),
     split_dwarf_kind: SplitDwarfKind = (SplitDwarfKind::Split, parse_split_dwarf_kind, [UNTRACKED],
@@ -1524,6 +1547,8 @@
         "choose the TLS model to use (`rustc --print tls-models` for details)"),
     trace_macros: bool = (false, parse_bool, [UNTRACKED],
         "for every macro invocation, print its name and arguments (default: no)"),
+    translate_remapped_path_to_local_path: bool = (true, parse_bool, [TRACKED],
+        "translate remapped paths into local paths when possible (default: yes)"),
     trap_unreachable: Option<bool> = (None, parse_opt_bool, [TRACKED],
         "generate trap instructions for unreachable intrinsics (default: use target setting, usually yes)"),
     treat_err_as_bug: Option<NonZeroUsize> = (None, parse_treat_err_as_bug, [TRACKED],
@@ -1560,6 +1585,9 @@
         "in general, enable more debug printouts (default: no)"),
     verify_llvm_ir: bool = (false, parse_bool, [TRACKED],
         "verify LLVM IR (default: no)"),
+    virtual_function_elimination: bool = (false, parse_bool, [TRACKED],
+        "enables dead virtual function elimination optimization. \
+        Requires `-Clto[=[fat,yes]]`"),
     wasi_exec_model: Option<WasiExecModel> = (None, parse_wasi_exec_model, [TRACKED],
         "whether to build a wasi command or reactor"),
 
diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs
index 6fb87e1..a5ccae0 100644
--- a/compiler/rustc_session/src/parse.rs
+++ b/compiler/rustc_session/src/parse.rs
@@ -311,6 +311,7 @@
         self.create_warning(warning).emit()
     }
 
+    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
     pub fn struct_err(
         &self,
         msg: impl Into<DiagnosticMessage>,
@@ -318,6 +319,7 @@
         self.span_diagnostic.struct_err(msg)
     }
 
+    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
     pub fn struct_warn(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
         self.span_diagnostic.struct_warn(msg)
     }
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index b2c23cd..f1814ee 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -209,6 +209,7 @@
 
 /// Trait implemented by error types. This should not be implemented manually. Instead, use
 /// `#[derive(SessionDiagnostic)]` -- see [rustc_macros::SessionDiagnostic].
+#[rustc_diagnostic_item = "SessionDiagnostic"]
 pub trait SessionDiagnostic<'a, T: EmissionGuarantee = ErrorGuaranteed> {
     /// Write out as a diagnostic out of `sess`.
     #[must_use]
@@ -286,6 +287,14 @@
     ) -> DiagnosticBuilder<'_, ()> {
         self.diagnostic().struct_span_warn(sp, msg)
     }
+    pub fn struct_span_warn_with_expectation<S: Into<MultiSpan>>(
+        &self,
+        sp: S,
+        msg: impl Into<DiagnosticMessage>,
+        id: lint::LintExpectationId,
+    ) -> DiagnosticBuilder<'_, ()> {
+        self.diagnostic().struct_span_warn_with_expectation(sp, msg, id)
+    }
     pub fn struct_span_warn_with_code<S: Into<MultiSpan>>(
         &self,
         sp: S,
@@ -297,6 +306,13 @@
     pub fn struct_warn(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
         self.diagnostic().struct_warn(msg)
     }
+    pub fn struct_warn_with_expectation(
+        &self,
+        msg: impl Into<DiagnosticMessage>,
+        id: lint::LintExpectationId,
+    ) -> DiagnosticBuilder<'_, ()> {
+        self.diagnostic().struct_warn_with_expectation(msg, id)
+    }
     pub fn struct_span_allow<S: Into<MultiSpan>>(
         &self,
         sp: S,
@@ -1252,7 +1268,8 @@
         let profiler = SelfProfiler::new(
             directory,
             sopts.crate_name.as_deref(),
-            &sopts.debugging_opts.self_profile_events,
+            sopts.debugging_opts.self_profile_events.as_ref().map(|xs| &xs[..]),
+            &sopts.debugging_opts.self_profile_counter,
         );
         match profiler {
             Ok(profiler) => Some(Arc::new(profiler)),
@@ -1431,14 +1448,14 @@
         );
     }
 
-    // LLVM CFI requires LTO.
-    if sess.is_sanitizer_cfi_enabled() {
-        if sess.opts.cg.lto == config::LtoCli::Unspecified
-            || sess.opts.cg.lto == config::LtoCli::No
-            || sess.opts.cg.lto == config::LtoCli::Thin
-        {
+    // LLVM CFI and VFE both require LTO.
+    if sess.lto() != config::Lto::Fat {
+        if sess.is_sanitizer_cfi_enabled() {
             sess.err("`-Zsanitizer=cfi` requires `-Clto`");
         }
+        if sess.opts.debugging_opts.virtual_function_elimination {
+            sess.err("`-Zvirtual-function-elimination` requires `-Clto`");
+        }
     }
 
     if sess.opts.debugging_opts.stack_protector != StackProtector::None {
diff --git a/compiler/rustc_session/src/utils.rs b/compiler/rustc_session/src/utils.rs
index db755cc..bda7b31 100644
--- a/compiler/rustc_session/src/utils.rs
+++ b/compiler/rustc_session/src/utils.rs
@@ -1,13 +1,7 @@
-use crate::parse::ParseSess;
 use crate::session::Session;
-use rustc_ast::token::{self, Delimiter, Nonterminal, Token};
-use rustc_ast::tokenstream::CanSynthesizeMissingTokens;
-use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree};
 use rustc_data_structures::profiling::VerboseTimingGuard;
 use std::path::{Path, PathBuf};
 
-pub type NtToTokenstream = fn(&Nonterminal, &ParseSess, CanSynthesizeMissingTokens) -> TokenStream;
-
 impl Session {
     pub fn timer<'a>(&'a self, what: &'static str) -> VerboseTimingGuard<'a> {
         self.prof.verbose_generic_activity(what)
@@ -94,55 +88,3 @@
         &self.original
     }
 }
-
-// FIXME: Find a better spot for this - it needs to be accessible from `rustc_ast_lowering`,
-// and needs to access `ParseSess
-pub struct FlattenNonterminals<'a> {
-    pub parse_sess: &'a ParseSess,
-    pub synthesize_tokens: CanSynthesizeMissingTokens,
-    pub nt_to_tokenstream: NtToTokenstream,
-}
-
-impl<'a> FlattenNonterminals<'a> {
-    pub fn process_token_stream(&mut self, tokens: TokenStream) -> TokenStream {
-        fn can_skip(stream: &TokenStream) -> bool {
-            stream.trees().all(|tree| match tree {
-                TokenTree::Token(token) => !matches!(token.kind, token::Interpolated(_)),
-                TokenTree::Delimited(_, _, inner) => can_skip(&inner),
-            })
-        }
-
-        if can_skip(&tokens) {
-            return tokens;
-        }
-
-        tokens.into_trees().flat_map(|tree| self.process_token_tree(tree).into_trees()).collect()
-    }
-
-    pub fn process_token_tree(&mut self, tree: TokenTree) -> TokenStream {
-        match tree {
-            TokenTree::Token(token) => self.process_token(token),
-            TokenTree::Delimited(span, delim, tts) => {
-                TokenTree::Delimited(span, delim, self.process_token_stream(tts)).into()
-            }
-        }
-    }
-
-    pub fn process_token(&mut self, token: Token) -> TokenStream {
-        match token.kind {
-            token::Interpolated(nt) if let token::NtIdent(ident, is_raw) = *nt => {
-                TokenTree::Token(Token::new(token::Ident(ident.name, is_raw), ident.span)).into()
-            }
-            token::Interpolated(nt) => {
-                let tts = (self.nt_to_tokenstream)(&nt, self.parse_sess, self.synthesize_tokens);
-                TokenTree::Delimited(
-                    DelimSpan::from_single(token.span),
-                    Delimiter::Invisible,
-                    self.process_token_stream(tts),
-                )
-                .into()
-            }
-            _ => TokenTree::Token(token).into(),
-        }
-    }
-}
diff --git a/compiler/rustc_smir/Cargo.toml b/compiler/rustc_smir/Cargo.toml
new file mode 100644
index 0000000..5e0d1f3
--- /dev/null
+++ b/compiler/rustc_smir/Cargo.toml
@@ -0,0 +1,28 @@
+[package]
+name = "rustc_smir"
+version = "0.0.0"
+edition = "2021"
+
+[dependencies]
+rustc_borrowck = { path = "../rustc_borrowck", optional = true }
+rustc_driver = { path = "../rustc_driver", optional = true }
+rustc_hir = { path = "../rustc_hir", optional = true }
+rustc_interface = { path = "../rustc_interface", optional = true }
+rustc_middle = { path = "../rustc_middle", optional = true }
+rustc_mir_dataflow = { path = "../rustc_mir_dataflow", optional = true }
+rustc_mir_transform = { path = "../rustc_mir_transform", optional = true }
+rustc_serialize = { path = "../rustc_serialize", optional = true }
+rustc_trait_selection = { path = "../rustc_trait_selection", optional = true }
+
+[features]
+default = [
+    "rustc_borrowck",
+    "rustc_driver",
+    "rustc_hir",
+    "rustc_interface",
+    "rustc_middle",
+    "rustc_mir_dataflow",
+    "rustc_mir_transform",
+    "rustc_serialize",
+    "rustc_trait_selection",
+]
diff --git a/compiler/rustc_smir/README.md b/compiler/rustc_smir/README.md
new file mode 100644
index 0000000..ae49098
--- /dev/null
+++ b/compiler/rustc_smir/README.md
@@ -0,0 +1,75 @@
+This crate is regularly synced with its mirror in the rustc repo at `compiler/rustc_smir`.
+
+We use `git subtree` for this to preserve commits and allow the rustc repo to
+edit these crates without having to touch this repo. This keeps the crates compiling
+while allowing us to independently work on them here. The effort of keeping them in
+sync is pushed entirely onto us, without affecting rustc workflows negatively.
+This may change in the future, but changes to policy should only be done via a
+compiler team MCP.
+
+## Instructions for working on this crate locally
+
+Since the crate is the same in the rustc repo and here, the dependencies on rustc_* crates
+will only either work here or there, but never in both places at the same time. Thus we use
+optional dependencies on the rustc_* crates, requiring local development to use
+
+```
+cargo build --no-default-features -Zavoid-dev-deps
+```
+
+in order to compile successfully.
+
+## Instructions for syncing
+
+### Updating this repository
+
+In the rustc repo, execute
+
+```
+git subtree push --prefix=compiler/rustc_smir url_to_your_fork_of_project_stable_mir some_feature_branch
+```
+
+and then open a PR of your `some_feature_branch` against https://github.com/rust-lang/project-stable-mir
+
+### Updating the rustc library
+
+First we need to bump our stack limit, as the rustc repo otherwise quickly hits that:
+
+```
+ulimit -s 60000
+```
+
+#### Maximum function recursion depth (1000) reached
+
+Then we need to disable `dash` as the default shell for sh scripts, as otherwise we run into a
+hard limit of a recursion depth of 1000:
+
+```
+sudo dpkg-reconfigure dash
+```
+
+and then select `No` to disable dash.
+
+
+#### Patching your `git worktree`
+
+The regular git worktree does not scale to repos of the size of the rustc repo.
+So download the `git-subtree.sh` from https://github.com/gitgitgadget/git/pull/493/files and run
+
+```
+sudo cp --backup /path/to/patched/git-subtree.sh /usr/lib/git-core/git-subtree
+sudo chmod --reference=/usr/lib/git-core/git-subtree~ /usr/lib/git-core/git-subtree
+sudo chown --reference=/usr/lib/git-core/git-subtree~ /usr/lib/git-core/git-subtree
+```
+
+#### Actually doing a sync
+
+In the rustc repo, execute
+
+```
+git subtree pull --prefix=compiler/rustc_smir https://github.com/rust-lang/project-stable-mir smir
+```
+
+Note: only ever sync to rustc from the project-stable-mir's `smir` branch. Do not sync with your own forks.
+
+Then open a PR against rustc just like a regular PR.
diff --git a/compiler/rustc_smir/rust-toolchain.toml b/compiler/rustc_smir/rust-toolchain.toml
new file mode 100644
index 0000000..7b696fc
--- /dev/null
+++ b/compiler/rustc_smir/rust-toolchain.toml
@@ -0,0 +1,3 @@
+[toolchain]
+channel = "nightly-2022-06-01"
+components = [ "rustfmt", "rustc-dev" ]
diff --git a/compiler/rustc_smir/src/lib.rs b/compiler/rustc_smir/src/lib.rs
new file mode 100644
index 0000000..5c7aaf3
--- /dev/null
+++ b/compiler/rustc_smir/src/lib.rs
@@ -0,0 +1,17 @@
+//! The WIP stable interface to rustc internals.
+//!
+//! For more information see https://github.com/rust-lang/project-stable-mir
+//!
+//! # Note
+//!
+//! This API is still completely unstable and subject to change.
+
+#![doc(
+    html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/",
+    test(attr(allow(unused_variables), deny(warnings)))
+)]
+#![cfg_attr(not(feature = "default"), feature(rustc_private))]
+
+pub mod mir;
+
+pub mod very_unstable;
diff --git a/compiler/rustc_smir/src/mir.rs b/compiler/rustc_smir/src/mir.rs
new file mode 100644
index 0000000..855605b
--- /dev/null
+++ b/compiler/rustc_smir/src/mir.rs
@@ -0,0 +1,10 @@
+pub use crate::very_unstable::middle::mir::{
+    visit::MutVisitor, AggregateKind, AssertKind, BasicBlock, BasicBlockData, BinOp, BindingForm,
+    BlockTailInfo, Body, BorrowKind, CastKind, ClearCrossCrate, Constant, ConstantKind,
+    CopyNonOverlapping, Coverage, FakeReadCause, Field, GeneratorInfo, ImplicitSelfKind,
+    InlineAsmOperand, Local, LocalDecl, LocalInfo, LocalKind, Location, MirPhase, MirSource,
+    NullOp, Operand, Place, PlaceRef, ProjectionElem, ProjectionKind, Promoted, RetagKind, Rvalue,
+    Safety, SourceInfo, SourceScope, SourceScopeData, SourceScopeLocalData, Statement,
+    StatementKind, UnOp, UserTypeProjection, UserTypeProjections, VarBindingForm, VarDebugInfo,
+    VarDebugInfoContents,
+};
diff --git a/compiler/rustc_smir/src/very_unstable.rs b/compiler/rustc_smir/src/very_unstable.rs
new file mode 100644
index 0000000..12ba133
--- /dev/null
+++ b/compiler/rustc_smir/src/very_unstable.rs
@@ -0,0 +1,27 @@
+//! This module reexports various crates and modules from unstable rustc APIs.
+//! Add anything you need here and it will get slowly transferred to a stable API.
+//! Only use rustc_smir in your dependencies and use the reexports here instead of
+//! directly referring to the unstable crates.
+
+macro_rules! crates {
+    ($($rustc_name:ident -> $name:ident,)*) => {
+        $(
+            #[cfg(not(feature = "default"))]
+            pub extern crate $rustc_name as $name;
+            #[cfg(feature = "default")]
+            pub use $rustc_name as $name;
+        )*
+    }
+}
+
+crates! {
+    rustc_borrowck -> borrowck,
+    rustc_driver -> driver,
+    rustc_hir -> hir,
+    rustc_interface -> interface,
+    rustc_middle -> middle,
+    rustc_mir_dataflow -> dataflow,
+    rustc_mir_transform -> transform,
+    rustc_serialize -> serialize,
+    rustc_trait_selection -> trait_selection,
+}
diff --git a/compiler/rustc_span/src/def_id.rs b/compiler/rustc_span/src/def_id.rs
index 3976c06..a1533fe 100644
--- a/compiler/rustc_span/src/def_id.rs
+++ b/compiler/rustc_span/src/def_id.rs
@@ -41,8 +41,8 @@
 /// As a local identifier, a `CrateNum` is only meaningful within its context, e.g. within a tcx.
 /// Therefore, make sure to include the context when encode a `CrateNum`.
 impl<E: Encoder> Encodable<E> for CrateNum {
-    default fn encode(&self, s: &mut E) -> Result<(), E::Error> {
-        s.emit_u32(self.as_u32())
+    default fn encode(&self, s: &mut E) {
+        s.emit_u32(self.as_u32());
     }
 }
 
@@ -203,7 +203,7 @@
 }
 
 impl<E: Encoder> Encodable<E> for DefIndex {
-    default fn encode(&self, _: &mut E) -> Result<(), E::Error> {
+    default fn encode(&self, _: &mut E) {
         panic!("cannot encode `DefIndex` with `{}`", std::any::type_name::<E>());
     }
 }
@@ -306,12 +306,9 @@
 }
 
 impl<E: Encoder> Encodable<E> for DefId {
-    default fn encode(&self, s: &mut E) -> Result<(), E::Error> {
-        s.emit_struct(false, |s| {
-            s.emit_struct_field("krate", true, |s| self.krate.encode(s))?;
-
-            s.emit_struct_field("index", false, |s| self.index.encode(s))
-        })
+    default fn encode(&self, s: &mut E) {
+        self.krate.encode(s);
+        self.index.encode(s);
     }
 }
 
@@ -385,8 +382,8 @@
 }
 
 impl<E: Encoder> Encodable<E> for LocalDefId {
-    fn encode(&self, s: &mut E) -> Result<(), E::Error> {
-        self.to_def_id().encode(s)
+    fn encode(&self, s: &mut E) {
+        self.to_def_id().encode(s);
     }
 }
 
diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs
index f194cf5..955db72 100644
--- a/compiler/rustc_span/src/hygiene.rs
+++ b/compiler/rustc_span/src/hygiene.rs
@@ -352,7 +352,7 @@
 }
 
 impl HygieneData {
-    crate fn new(edition: Edition) -> Self {
+    pub(crate) fn new(edition: Edition) -> Self {
         let root_data = ExpnData::default(
             ExpnKind::Root,
             DUMMY_SP,
@@ -668,17 +668,17 @@
     }
 
     #[inline]
-    crate fn as_u32(self) -> u32 {
+    pub(crate) fn as_u32(self) -> u32 {
         self.0
     }
 
     #[inline]
-    crate fn from_u32(raw: u32) -> SyntaxContext {
+    pub(crate) fn from_u32(raw: u32) -> SyntaxContext {
         SyntaxContext(raw)
     }
 
     /// Extend a syntax context with a given expansion and transparency.
-    crate fn apply_mark(self, expn_id: ExpnId, transparency: Transparency) -> SyntaxContext {
+    pub(crate) fn apply_mark(self, expn_id: ExpnId, transparency: Transparency) -> SyntaxContext {
         HygieneData::with(|data| data.apply_mark(self, expn_id, transparency))
     }
 
@@ -1189,12 +1189,12 @@
         }
     }
 
-    pub fn encode<T, R>(
+    pub fn encode<T>(
         &self,
         encoder: &mut T,
-        mut encode_ctxt: impl FnMut(&mut T, u32, &SyntaxContextData) -> Result<(), R>,
-        mut encode_expn: impl FnMut(&mut T, ExpnId, &ExpnData, ExpnHash) -> Result<(), R>,
-    ) -> Result<(), R> {
+        mut encode_ctxt: impl FnMut(&mut T, u32, &SyntaxContextData),
+        mut encode_expn: impl FnMut(&mut T, ExpnId, &ExpnData, ExpnHash),
+    ) {
         // When we serialize a `SyntaxContextData`, we may end up serializing
         // a `SyntaxContext` that we haven't seen before
         while !self.latest_ctxts.lock().is_empty() || !self.latest_expns.lock().is_empty() {
@@ -1213,22 +1213,19 @@
             // order
             for_all_ctxts_in(latest_ctxts.into_iter(), |index, ctxt, data| {
                 if self.serialized_ctxts.lock().insert(ctxt) {
-                    encode_ctxt(encoder, index, data)?;
+                    encode_ctxt(encoder, index, data);
                 }
-                Ok(())
-            })?;
+            });
 
             let latest_expns = { std::mem::take(&mut *self.latest_expns.lock()) };
 
             for_all_expns_in(latest_expns.into_iter(), |expn, data, hash| {
                 if self.serialized_expns.lock().insert(expn) {
-                    encode_expn(encoder, expn, data, hash)?;
+                    encode_expn(encoder, expn, data, hash);
                 }
-                Ok(())
-            })?;
+            });
         }
         debug!("encode_hygiene: Done serializing SyntaxContextData");
-        Ok(())
     }
 }
 
@@ -1378,40 +1375,38 @@
     new_ctxt
 }
 
-fn for_all_ctxts_in<E, F: FnMut(u32, SyntaxContext, &SyntaxContextData) -> Result<(), E>>(
+fn for_all_ctxts_in<F: FnMut(u32, SyntaxContext, &SyntaxContextData)>(
     ctxts: impl Iterator<Item = SyntaxContext>,
     mut f: F,
-) -> Result<(), E> {
+) {
     let all_data: Vec<_> = HygieneData::with(|data| {
         ctxts.map(|ctxt| (ctxt, data.syntax_context_data[ctxt.0 as usize].clone())).collect()
     });
     for (ctxt, data) in all_data.into_iter() {
-        f(ctxt.0, ctxt, &data)?;
+        f(ctxt.0, ctxt, &data);
     }
-    Ok(())
 }
 
-fn for_all_expns_in<E>(
+fn for_all_expns_in(
     expns: impl Iterator<Item = ExpnId>,
-    mut f: impl FnMut(ExpnId, &ExpnData, ExpnHash) -> Result<(), E>,
-) -> Result<(), E> {
+    mut f: impl FnMut(ExpnId, &ExpnData, ExpnHash),
+) {
     let all_data: Vec<_> = HygieneData::with(|data| {
         expns.map(|expn| (expn, data.expn_data(expn).clone(), data.expn_hash(expn))).collect()
     });
     for (expn, data, hash) in all_data.into_iter() {
-        f(expn, &data, hash)?;
+        f(expn, &data, hash);
     }
-    Ok(())
 }
 
 impl<E: Encoder> Encodable<E> for LocalExpnId {
-    fn encode(&self, e: &mut E) -> Result<(), E::Error> {
-        self.to_expn_id().encode(e)
+    fn encode(&self, e: &mut E) {
+        self.to_expn_id().encode(e);
     }
 }
 
 impl<E: Encoder> Encodable<E> for ExpnId {
-    default fn encode(&self, _: &mut E) -> Result<(), E::Error> {
+    default fn encode(&self, _: &mut E) {
         panic!("cannot encode `ExpnId` with `{}`", std::any::type_name::<E>());
     }
 }
@@ -1432,15 +1427,15 @@
     ctxt: SyntaxContext,
     context: &HygieneEncodeContext,
     e: &mut E,
-) -> Result<(), E::Error> {
+) {
     if !context.serialized_ctxts.lock().contains(&ctxt) {
         context.latest_ctxts.lock().insert(ctxt);
     }
-    ctxt.0.encode(e)
+    ctxt.0.encode(e);
 }
 
 impl<E: Encoder> Encodable<E> for SyntaxContext {
-    default fn encode(&self, _: &mut E) -> Result<(), E::Error> {
+    default fn encode(&self, _: &mut E) {
         panic!("cannot encode `SyntaxContext` with `{}`", std::any::type_name::<E>());
     }
 }
diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs
index 7357ceb..a329fa1 100644
--- a/compiler/rustc_span/src/lib.rs
+++ b/compiler/rustc_span/src/lib.rs
@@ -15,11 +15,9 @@
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![feature(array_windows)]
-#![feature(crate_visibility_modifier)]
 #![feature(let_else)]
 #![feature(if_let_guard)]
 #![feature(negative_impls)]
-#![feature(nll)]
 #![feature(min_specialization)]
 #![feature(rustc_attrs)]
 #![allow(rustc::potential_query_instability)]
@@ -196,25 +194,21 @@
 // This is functionally identical to #[derive(Encodable)], with the exception of
 // an added assert statement
 impl<S: Encoder> Encodable<S> for RealFileName {
-    fn encode(&self, encoder: &mut S) -> Result<(), S::Error> {
-        encoder.emit_enum(|encoder| match *self {
-            RealFileName::LocalPath(ref local_path) => {
-                encoder.emit_enum_variant("LocalPath", 0, 1, |encoder| {
-                    encoder.emit_enum_variant_arg(true, |encoder| local_path.encode(encoder))?;
-                    Ok(())
-                })
-            }
+    fn encode(&self, encoder: &mut S) {
+        match *self {
+            RealFileName::LocalPath(ref local_path) => encoder.emit_enum_variant(0, |encoder| {
+                local_path.encode(encoder);
+            }),
 
             RealFileName::Remapped { ref local_path, ref virtual_name } => encoder
-                .emit_enum_variant("Remapped", 1, 2, |encoder| {
+                .emit_enum_variant(1, |encoder| {
                     // For privacy and build reproducibility, we must not embed host-dependant path in artifacts
                     // if they have been remapped by --remap-path-prefix
                     assert!(local_path.is_none());
-                    encoder.emit_enum_variant_arg(true, |encoder| local_path.encode(encoder))?;
-                    encoder.emit_enum_variant_arg(false, |encoder| virtual_name.encode(encoder))?;
-                    Ok(())
+                    local_path.encode(encoder);
+                    virtual_name.encode(encoder);
                 }),
-        })
+        }
     }
 }
 
@@ -335,11 +329,11 @@
     }
 }
 
-impl FileNameDisplay<'_> {
-    pub fn to_string_lossy(&self) -> Cow<'_, str> {
+impl<'a> FileNameDisplay<'a> {
+    pub fn to_string_lossy(&self) -> Cow<'a, str> {
         match self.inner {
             FileName::Real(ref inner) => inner.to_string_lossy(self.display_pref),
-            _ => Cow::from(format!("{}", self)),
+            _ => Cow::from(self.to_string()),
         }
     }
 }
@@ -543,6 +537,9 @@
     pub fn ctxt(self) -> SyntaxContext {
         self.data_untracked().ctxt
     }
+    pub fn eq_ctxt(self, other: Span) -> bool {
+        self.data_untracked().ctxt == other.data_untracked().ctxt
+    }
     #[inline]
     pub fn with_ctxt(self, ctxt: SyntaxContext) -> Span {
         self.data_untracked().with_ctxt(ctxt)
@@ -949,12 +946,10 @@
 }
 
 impl<E: Encoder> Encodable<E> for Span {
-    default fn encode(&self, s: &mut E) -> Result<(), E::Error> {
+    default fn encode(&self, s: &mut E) {
         let span = self.data();
-        s.emit_struct(false, |s| {
-            s.emit_struct_field("lo", true, |s| span.lo.encode(s))?;
-            s.emit_struct_field("hi", false, |s| span.hi.encode(s))
-        })
+        span.lo.encode(s);
+        span.hi.encode(s);
     }
 }
 impl<D: Decoder> Decodable<D> for Span {
@@ -1153,7 +1148,7 @@
 }
 
 /// The hash of the on-disk source file used for debug info.
-#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
 #[derive(HashStable_Generic, Encodable, Decodable)]
 pub struct SourceFileHash {
     pub kind: SourceFileHashAlgorithm,
@@ -1204,6 +1199,7 @@
 #[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, Encodable, Decodable)]
 pub enum DebuggerVisualizerType {
     Natvis,
+    GdbPrettyPrinter,
 }
 
 /// A single debugger visualizer file.
@@ -1222,6 +1218,52 @@
     }
 }
 
+#[derive(Clone)]
+pub enum SourceFileLines {
+    /// The source file lines, in decoded (random-access) form.
+    Lines(Vec<BytePos>),
+
+    /// The source file lines, in undecoded difference list form.
+    Diffs(SourceFileDiffs),
+}
+
+impl SourceFileLines {
+    pub fn is_lines(&self) -> bool {
+        matches!(self, SourceFileLines::Lines(_))
+    }
+}
+
+/// The source file lines in difference list form. This matches the form
+/// used within metadata, which saves space by exploiting the fact that the
+/// lines list is sorted and individual lines are usually not that long.
+///
+/// We read it directly from metadata and only decode it into `Lines` form
+/// when necessary. This is a significant performance win, especially for
+/// small crates where very little of `std`'s metadata is used.
+#[derive(Clone)]
+pub struct SourceFileDiffs {
+    /// Position of the first line. Note that this is always encoded as a
+    /// `BytePos` because it is often much larger than any of the
+    /// differences.
+    line_start: BytePos,
+
+    /// Always 1, 2, or 4. Always as small as possible, while being big
+    /// enough to hold the length of the longest line in the source file.
+    /// The 1 case is by far the most common.
+    bytes_per_diff: usize,
+
+    /// The number of diffs encoded in `raw_diffs`. Always one less than
+    /// the number of lines in the source file.
+    num_diffs: usize,
+
+    /// The diffs in "raw" form. Each segment of `bytes_per_diff` length
+    /// encodes one little-endian diff. Note that they aren't LEB128
+    /// encoded. This makes for much faster decoding. Besides, the
+    /// bytes_per_diff==1 case is by far the most common, and LEB128
+    /// encoding has no effect on that case.
+    raw_diffs: Vec<u8>,
+}
+
 /// A single source in the [`SourceMap`].
 #[derive(Clone)]
 pub struct SourceFile {
@@ -1241,7 +1283,7 @@
     /// The end position of this source in the `SourceMap`.
     pub end_pos: BytePos,
     /// Locations of lines beginnings in the source code.
-    pub lines: Vec<BytePos>,
+    pub lines: Lock<SourceFileLines>,
     /// Locations of multi-byte characters in the source code.
     pub multibyte_chars: Vec<MultiByteChar>,
     /// Width of characters that are not narrow in the source code.
@@ -1255,76 +1297,77 @@
 }
 
 impl<S: Encoder> Encodable<S> for SourceFile {
-    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
-        s.emit_struct(false, |s| {
-            s.emit_struct_field("name", true, |s| self.name.encode(s))?;
-            s.emit_struct_field("src_hash", false, |s| self.src_hash.encode(s))?;
-            s.emit_struct_field("start_pos", false, |s| self.start_pos.encode(s))?;
-            s.emit_struct_field("end_pos", false, |s| self.end_pos.encode(s))?;
-            s.emit_struct_field("lines", false, |s| {
-                let lines = &self.lines[..];
-                // Store the length.
-                s.emit_u32(lines.len() as u32)?;
+    fn encode(&self, s: &mut S) {
+        self.name.encode(s);
+        self.src_hash.encode(s);
+        self.start_pos.encode(s);
+        self.end_pos.encode(s);
 
-                if !lines.is_empty() {
-                    // In order to preserve some space, we exploit the fact that
-                    // the lines list is sorted and individual lines are
-                    // probably not that long. Because of that we can store lines
-                    // as a difference list, using as little space as possible
-                    // for the differences.
-                    let max_line_length = if lines.len() == 1 {
-                        0
-                    } else {
-                        lines
-                            .array_windows()
-                            .map(|&[fst, snd]| snd - fst)
-                            .map(|bp| bp.to_usize())
-                            .max()
-                            .unwrap()
-                    };
+        // We are always in `Lines` form by the time we reach here.
+        assert!(self.lines.borrow().is_lines());
+        self.lines(|lines| {
+            // Store the length.
+            s.emit_u32(lines.len() as u32);
 
-                    let bytes_per_diff: u8 = match max_line_length {
-                        0..=0xFF => 1,
-                        0x100..=0xFFFF => 2,
-                        _ => 4,
-                    };
+            // Compute and store the difference list.
+            if lines.len() != 0 {
+                let max_line_length = if lines.len() == 1 {
+                    0
+                } else {
+                    lines
+                        .array_windows()
+                        .map(|&[fst, snd]| snd - fst)
+                        .map(|bp| bp.to_usize())
+                        .max()
+                        .unwrap()
+                };
 
-                    // Encode the number of bytes used per diff.
-                    bytes_per_diff.encode(s)?;
+                let bytes_per_diff: usize = match max_line_length {
+                    0..=0xFF => 1,
+                    0x100..=0xFFFF => 2,
+                    _ => 4,
+                };
 
-                    // Encode the first element.
-                    lines[0].encode(s)?;
+                // Encode the number of bytes used per diff.
+                s.emit_u8(bytes_per_diff as u8);
 
-                    let diff_iter = lines.array_windows().map(|&[fst, snd]| snd - fst);
+                // Encode the first element.
+                lines[0].encode(s);
 
-                    match bytes_per_diff {
-                        1 => {
-                            for diff in diff_iter {
-                                (diff.0 as u8).encode(s)?
-                            }
+                // Encode the difference list.
+                let diff_iter = lines.array_windows().map(|&[fst, snd]| snd - fst);
+                let num_diffs = lines.len() - 1;
+                let mut raw_diffs;
+                match bytes_per_diff {
+                    1 => {
+                        raw_diffs = Vec::with_capacity(num_diffs);
+                        for diff in diff_iter {
+                            raw_diffs.push(diff.0 as u8);
                         }
-                        2 => {
-                            for diff in diff_iter {
-                                (diff.0 as u16).encode(s)?
-                            }
-                        }
-                        4 => {
-                            for diff in diff_iter {
-                                diff.0.encode(s)?
-                            }
-                        }
-                        _ => unreachable!(),
                     }
+                    2 => {
+                        raw_diffs = Vec::with_capacity(bytes_per_diff * num_diffs);
+                        for diff in diff_iter {
+                            raw_diffs.extend_from_slice(&(diff.0 as u16).to_le_bytes());
+                        }
+                    }
+                    4 => {
+                        raw_diffs = Vec::with_capacity(bytes_per_diff * num_diffs);
+                        for diff in diff_iter {
+                            raw_diffs.extend_from_slice(&(diff.0 as u32).to_le_bytes());
+                        }
+                    }
+                    _ => unreachable!(),
                 }
+                s.emit_raw_bytes(&raw_diffs);
+            }
+        });
 
-                Ok(())
-            })?;
-            s.emit_struct_field("multibyte_chars", false, |s| self.multibyte_chars.encode(s))?;
-            s.emit_struct_field("non_narrow_chars", false, |s| self.non_narrow_chars.encode(s))?;
-            s.emit_struct_field("name_hash", false, |s| self.name_hash.encode(s))?;
-            s.emit_struct_field("normalized_pos", false, |s| self.normalized_pos.encode(s))?;
-            s.emit_struct_field("cnum", false, |s| self.cnum.encode(s))
-        })
+        self.multibyte_chars.encode(s);
+        self.non_narrow_chars.encode(s);
+        self.name_hash.encode(s);
+        self.normalized_pos.encode(s);
+        self.cnum.encode(s);
     }
 }
 
@@ -1334,36 +1377,27 @@
         let src_hash: SourceFileHash = Decodable::decode(d);
         let start_pos: BytePos = Decodable::decode(d);
         let end_pos: BytePos = Decodable::decode(d);
-        let lines: Vec<BytePos> = {
+        let lines = {
             let num_lines: u32 = Decodable::decode(d);
-            let mut lines = Vec::with_capacity(num_lines as usize);
-
             if num_lines > 0 {
                 // Read the number of bytes used per diff.
-                let bytes_per_diff: u8 = Decodable::decode(d);
+                let bytes_per_diff = d.read_u8() as usize;
 
                 // Read the first element.
-                let mut line_start: BytePos = Decodable::decode(d);
-                lines.push(line_start);
+                let line_start: BytePos = Decodable::decode(d);
 
-                match bytes_per_diff {
-                    1 => lines.extend((1..num_lines).map(|_| {
-                        line_start = line_start + BytePos(d.read_u8() as u32);
-                        line_start
-                    })),
-                    2 => lines.extend((1..num_lines).map(|_| {
-                        line_start = line_start + BytePos(d.read_u16() as u32);
-                        line_start
-                    })),
-                    4 => lines.extend((1..num_lines).map(|_| {
-                        line_start = line_start + BytePos(d.read_u32());
-                        line_start
-                    })),
-                    _ => unreachable!(),
-                }
+                // Read the difference list.
+                let num_diffs = num_lines as usize - 1;
+                let raw_diffs = d.read_raw_bytes(bytes_per_diff * num_diffs).to_vec();
+                SourceFileLines::Diffs(SourceFileDiffs {
+                    line_start,
+                    bytes_per_diff,
+                    num_diffs,
+                    raw_diffs,
+                })
+            } else {
+                SourceFileLines::Lines(vec![])
             }
-
-            lines
         };
         let multibyte_chars: Vec<MultiByteChar> = Decodable::decode(d);
         let non_narrow_chars: Vec<NonNarrowChar> = Decodable::decode(d);
@@ -1379,7 +1413,7 @@
             // Unused - the metadata decoder will construct
             // a new SourceFile, filling in `external_src` properly
             external_src: Lock::new(ExternalSource::Unneeded),
-            lines,
+            lines: Lock::new(lines),
             multibyte_chars,
             non_narrow_chars,
             normalized_pos,
@@ -1424,7 +1458,7 @@
             external_src: Lock::new(ExternalSource::Unneeded),
             start_pos,
             end_pos: Pos::from_usize(end_pos),
-            lines,
+            lines: Lock::new(SourceFileLines::Lines(lines)),
             multibyte_chars,
             non_narrow_chars,
             normalized_pos,
@@ -1433,10 +1467,68 @@
         }
     }
 
+    pub fn lines<F, R>(&self, f: F) -> R
+    where
+        F: FnOnce(&[BytePos]) -> R,
+    {
+        let mut guard = self.lines.borrow_mut();
+        match &*guard {
+            SourceFileLines::Lines(lines) => f(lines),
+            SourceFileLines::Diffs(SourceFileDiffs {
+                mut line_start,
+                bytes_per_diff,
+                num_diffs,
+                raw_diffs,
+            }) => {
+                // Convert from "diffs" form to "lines" form.
+                let num_lines = num_diffs + 1;
+                let mut lines = Vec::with_capacity(num_lines);
+                lines.push(line_start);
+
+                assert_eq!(*num_diffs, raw_diffs.len() / bytes_per_diff);
+                match bytes_per_diff {
+                    1 => {
+                        lines.extend(raw_diffs.into_iter().map(|&diff| {
+                            line_start = line_start + BytePos(diff as u32);
+                            line_start
+                        }));
+                    }
+                    2 => {
+                        lines.extend((0..*num_diffs).map(|i| {
+                            let pos = bytes_per_diff * i;
+                            let bytes = [raw_diffs[pos], raw_diffs[pos + 1]];
+                            let diff = u16::from_le_bytes(bytes);
+                            line_start = line_start + BytePos(diff as u32);
+                            line_start
+                        }));
+                    }
+                    4 => {
+                        lines.extend((0..*num_diffs).map(|i| {
+                            let pos = bytes_per_diff * i;
+                            let bytes = [
+                                raw_diffs[pos],
+                                raw_diffs[pos + 1],
+                                raw_diffs[pos + 2],
+                                raw_diffs[pos + 3],
+                            ];
+                            let diff = u32::from_le_bytes(bytes);
+                            line_start = line_start + BytePos(diff);
+                            line_start
+                        }));
+                    }
+                    _ => unreachable!(),
+                }
+                let res = f(&lines);
+                *guard = SourceFileLines::Lines(lines);
+                res
+            }
+        }
+    }
+
     /// Returns the `BytePos` of the beginning of the current line.
     pub fn line_begin_pos(&self, pos: BytePos) -> BytePos {
         let line_index = self.lookup_line(pos).unwrap();
-        self.lines[line_index]
+        self.lines(|lines| lines[line_index])
     }
 
     /// Add externally loaded source.
@@ -1493,8 +1585,8 @@
         }
 
         let begin = {
-            let line = self.lines.get(line_number)?;
-            let begin: BytePos = *line - self.start_pos;
+            let line = self.lines(|lines| lines.get(line_number).copied())?;
+            let begin: BytePos = line - self.start_pos;
             begin.to_usize()
         };
 
@@ -1516,7 +1608,7 @@
     }
 
     pub fn count_lines(&self) -> usize {
-        self.lines.len()
+        self.lines(|lines| lines.len())
     }
 
     /// Finds the line containing the given position. The return value is the
@@ -1524,11 +1616,11 @@
     /// number. If the source_file is empty or the position is located before the
     /// first line, `None` is returned.
     pub fn lookup_line(&self, pos: BytePos) -> Option<usize> {
-        match self.lines.binary_search(&pos) {
+        self.lines(|lines| match lines.binary_search(&pos) {
             Ok(idx) => Some(idx),
             Err(0) => None,
             Err(idx) => Some(idx - 1),
-        }
+        })
     }
 
     pub fn line_bounds(&self, line_index: usize) -> Range<BytePos> {
@@ -1536,12 +1628,14 @@
             return self.start_pos..self.end_pos;
         }
 
-        assert!(line_index < self.lines.len());
-        if line_index == (self.lines.len() - 1) {
-            self.lines[line_index]..self.end_pos
-        } else {
-            self.lines[line_index]..self.lines[line_index + 1]
-        }
+        self.lines(|lines| {
+            assert!(line_index < lines.len());
+            if line_index == (lines.len() - 1) {
+                lines[line_index]..self.end_pos
+            } else {
+                lines[line_index]..lines[line_index + 1]
+            }
+        })
     }
 
     /// Returns whether or not the file contains the given `SourceMap` byte
@@ -1603,7 +1697,7 @@
         match self.lookup_line(pos) {
             Some(a) => {
                 let line = a + 1; // Line numbers start at 1
-                let linebpos = self.lines[a];
+                let linebpos = self.lines(|lines| lines[a]);
                 let linechpos = self.bytepos_to_file_charpos(linebpos);
                 let col = chpos - linechpos;
                 debug!("byte pos {:?} is on the line at byte pos {:?}", pos, linebpos);
@@ -1622,7 +1716,7 @@
         let (line, col_or_chpos) = self.lookup_file_pos(pos);
         if line > 0 {
             let col = col_or_chpos;
-            let linebpos = self.lines[line - 1];
+            let linebpos = self.lines(|lines| lines[line - 1]);
             let col_display = {
                 let start_width_idx = self
                     .non_narrow_chars
@@ -1820,13 +1914,13 @@
     pub struct CharPos(pub usize);
 }
 
-impl<S: rustc_serialize::Encoder> Encodable<S> for BytePos {
-    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
-        s.emit_u32(self.0)
+impl<S: Encoder> Encodable<S> for BytePos {
+    fn encode(&self, s: &mut S) {
+        s.emit_u32(self.0);
     }
 }
 
-impl<D: rustc_serialize::Decoder> Decodable<D> for BytePos {
+impl<D: Decoder> Decodable<D> for BytePos {
     fn decode(d: &mut D) -> BytePos {
         BytePos(d.read_u32())
     }
diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs
index 505c0af..95ea702 100644
--- a/compiler/rustc_span/src/source_map.rs
+++ b/compiler/rustc_span/src/source_map.rs
@@ -331,7 +331,7 @@
         name_hash: u128,
         source_len: usize,
         cnum: CrateNum,
-        mut file_local_lines: Vec<BytePos>,
+        file_local_lines: Lock<SourceFileLines>,
         mut file_local_multibyte_chars: Vec<MultiByteChar>,
         mut file_local_non_narrow_chars: Vec<NonNarrowChar>,
         mut file_local_normalized_pos: Vec<NormalizedPos>,
@@ -345,20 +345,34 @@
         let end_pos = Pos::from_usize(start_pos + source_len);
         let start_pos = Pos::from_usize(start_pos);
 
-        for pos in &mut file_local_lines {
-            *pos = *pos + start_pos;
+        // Translate these positions into the new global frame of reference,
+        // now that the offset of the SourceFile is known.
+        //
+        // These are all unsigned values. `original_start_pos` may be larger or
+        // smaller than `start_pos`, but `pos` is always larger than both.
+        // Therefore, `(pos - original_start_pos) + start_pos` won't overflow
+        // but `start_pos - original_start_pos` might. So we use the former
+        // form rather than pre-computing the offset into a local variable. The
+        // compiler backend can optimize away the repeated computations in a
+        // way that won't trigger overflow checks.
+        match &mut *file_local_lines.borrow_mut() {
+            SourceFileLines::Lines(lines) => {
+                for pos in lines {
+                    *pos = (*pos - original_start_pos) + start_pos;
+                }
+            }
+            SourceFileLines::Diffs(SourceFileDiffs { line_start, .. }) => {
+                *line_start = (*line_start - original_start_pos) + start_pos;
+            }
         }
-
         for mbc in &mut file_local_multibyte_chars {
-            mbc.pos = mbc.pos + start_pos;
+            mbc.pos = (mbc.pos - original_start_pos) + start_pos;
         }
-
         for swc in &mut file_local_non_narrow_chars {
-            *swc = *swc + start_pos;
+            *swc = (*swc - original_start_pos) + start_pos;
         }
-
         for nc in &mut file_local_normalized_pos {
-            nc.pos = nc.pos + start_pos;
+            nc.pos = (nc.pos - original_start_pos) + start_pos;
         }
 
         let source_file = Lrc::new(SourceFile {
@@ -1098,28 +1112,45 @@
     /// The return value is the remapped path and a boolean indicating whether
     /// the path was affected by the mapping.
     pub fn map_prefix(&self, path: PathBuf) -> (PathBuf, bool) {
-        // NOTE: We are iterating over the mapping entries from last to first
-        //       because entries specified later on the command line should
-        //       take precedence.
-        for &(ref from, ref to) in self.mapping.iter().rev() {
-            if let Ok(rest) = path.strip_prefix(from) {
-                let remapped = if rest.as_os_str().is_empty() {
-                    // This is subtle, joining an empty path onto e.g. `foo/bar` will
-                    // result in `foo/bar/`, that is, there'll be an additional directory
-                    // separator at the end. This can lead to duplicated directory separators
-                    // in remapped paths down the line.
-                    // So, if we have an exact match, we just return that without a call
-                    // to `Path::join()`.
-                    to.clone()
-                } else {
-                    to.join(rest)
-                };
-
-                return (remapped, true);
-            }
+        if path.as_os_str().is_empty() {
+            // Exit early if the path is empty and therefore there's nothing to remap.
+            // This is mostly to reduce spam for `RUSTC_LOG=[remap_path_prefix]`.
+            return (path, false);
         }
 
-        (path, false)
+        return remap_path_prefix(&self.mapping, path);
+
+        #[instrument(level = "debug", skip(mapping))]
+        fn remap_path_prefix(mapping: &[(PathBuf, PathBuf)], path: PathBuf) -> (PathBuf, bool) {
+            // NOTE: We are iterating over the mapping entries from last to first
+            //       because entries specified later on the command line should
+            //       take precedence.
+            for &(ref from, ref to) in mapping.iter().rev() {
+                debug!("Trying to apply {:?} => {:?}", from, to);
+
+                if let Ok(rest) = path.strip_prefix(from) {
+                    let remapped = if rest.as_os_str().is_empty() {
+                        // This is subtle, joining an empty path onto e.g. `foo/bar` will
+                        // result in `foo/bar/`, that is, there'll be an additional directory
+                        // separator at the end. This can lead to duplicated directory separators
+                        // in remapped paths down the line.
+                        // So, if we have an exact match, we just return that without a call
+                        // to `Path::join()`.
+                        to.clone()
+                    } else {
+                        to.join(rest)
+                    };
+                    debug!("Match - remapped {:?} => {:?}", path, remapped);
+
+                    return (remapped, true);
+                } else {
+                    debug!("No match - prefix {:?} does not match {:?}", from, path);
+                }
+            }
+
+            debug!("Path {:?} was not remapped", path);
+            (path, false)
+        }
     }
 
     fn map_filename_prefix(&self, file: &FileName) -> (FileName, bool) {
@@ -1140,4 +1171,83 @@
             other => (other.clone(), false),
         }
     }
+
+    /// Expand a relative path to an absolute path with remapping taken into account.
+    /// Use this when absolute paths are required (e.g. debuginfo or crate metadata).
+    ///
+    /// The resulting `RealFileName` will have its `local_path` portion erased if
+    /// possible (i.e. if there's also a remapped path).
+    pub fn to_embeddable_absolute_path(
+        &self,
+        file_path: RealFileName,
+        working_directory: &RealFileName,
+    ) -> RealFileName {
+        match file_path {
+            // Anything that's already remapped we don't modify, except for erasing
+            // the `local_path` portion.
+            RealFileName::Remapped { local_path: _, virtual_name } => {
+                RealFileName::Remapped {
+                    // We do not want any local path to be exported into metadata
+                    local_path: None,
+                    // We use the remapped name verbatim, even if it looks like a relative
+                    // path. The assumption is that the user doesn't want us to further
+                    // process paths that have gone through remapping.
+                    virtual_name,
+                }
+            }
+
+            RealFileName::LocalPath(unmapped_file_path) => {
+                // If no remapping has been applied yet, try to do so
+                let (new_path, was_remapped) = self.map_prefix(unmapped_file_path);
+                if was_remapped {
+                    // It was remapped, so don't modify further
+                    return RealFileName::Remapped { local_path: None, virtual_name: new_path };
+                }
+
+                if new_path.is_absolute() {
+                    // No remapping has applied to this path and it is absolute,
+                    // so the working directory cannot influence it either, so
+                    // we are done.
+                    return RealFileName::LocalPath(new_path);
+                }
+
+                debug_assert!(new_path.is_relative());
+                let unmapped_file_path_rel = new_path;
+
+                match working_directory {
+                    RealFileName::LocalPath(unmapped_working_dir_abs) => {
+                        let file_path_abs = unmapped_working_dir_abs.join(unmapped_file_path_rel);
+
+                        // Although neither `working_directory` nor the file name were subject
+                        // to path remapping, the concatenation between the two may be. Hence
+                        // we need to do a remapping here.
+                        let (file_path_abs, was_remapped) = self.map_prefix(file_path_abs);
+                        if was_remapped {
+                            RealFileName::Remapped {
+                                // Erase the actual path
+                                local_path: None,
+                                virtual_name: file_path_abs,
+                            }
+                        } else {
+                            // No kind of remapping applied to this path, so
+                            // we leave it as it is.
+                            RealFileName::LocalPath(file_path_abs)
+                        }
+                    }
+                    RealFileName::Remapped {
+                        local_path: _,
+                        virtual_name: remapped_working_dir_abs,
+                    } => {
+                        // If working_directory has been remapped, then we emit
+                        // Remapped variant as the expanded path won't be valid
+                        RealFileName::Remapped {
+                            local_path: None,
+                            virtual_name: Path::new(remapped_working_dir_abs)
+                                .join(unmapped_file_path_rel),
+                        }
+                    }
+                }
+            }
+        }
+    }
 }
diff --git a/compiler/rustc_span/src/source_map/tests.rs b/compiler/rustc_span/src/source_map/tests.rs
index 481e015..be827ce 100644
--- a/compiler/rustc_span/src/source_map/tests.rs
+++ b/compiler/rustc_span/src/source_map/tests.rs
@@ -313,82 +313,169 @@
     }
 }
 
-fn map_path_prefix(mapping: &FilePathMapping, path: &str) -> String {
+// Takes a unix-style path and returns a platform specific path.
+fn path(p: &str) -> PathBuf {
+    path_str(p).into()
+}
+
+// Takes a unix-style path and returns a platform specific path.
+fn path_str(p: &str) -> String {
+    #[cfg(not(windows))]
+    {
+        return p.into();
+    }
+
+    #[cfg(windows)]
+    {
+        let mut path = p.replace('/', "\\");
+        if let Some(rest) = path.strip_prefix('\\') {
+            path = ["X:\\", rest].concat();
+        }
+
+        path
+    }
+}
+
+fn map_path_prefix(mapping: &FilePathMapping, p: &str) -> String {
     // It's important that we convert to a string here because that's what
     // later stages do too (e.g. in the backend), and comparing `Path` values
     // won't catch some differences at the string level, e.g. "abc" and "abc/"
     // compare as equal.
-    mapping.map_prefix(path.into()).0.to_string_lossy().to_string()
+    mapping.map_prefix(path(p)).0.to_string_lossy().to_string()
 }
 
-#[cfg(unix)]
 #[test]
 fn path_prefix_remapping() {
     // Relative to relative
     {
-        let mapping = &FilePathMapping::new(vec![("abc/def".into(), "foo".into())]);
+        let mapping = &FilePathMapping::new(vec![(path("abc/def"), path("foo"))]);
 
-        assert_eq!(map_path_prefix(mapping, "abc/def/src/main.rs"), "foo/src/main.rs");
-        assert_eq!(map_path_prefix(mapping, "abc/def"), "foo");
+        assert_eq!(map_path_prefix(mapping, "abc/def/src/main.rs"), path_str("foo/src/main.rs"));
+        assert_eq!(map_path_prefix(mapping, "abc/def"), path_str("foo"));
     }
 
     // Relative to absolute
     {
-        let mapping = &FilePathMapping::new(vec![("abc/def".into(), "/foo".into())]);
+        let mapping = &FilePathMapping::new(vec![(path("abc/def"), path("/foo"))]);
 
-        assert_eq!(map_path_prefix(mapping, "abc/def/src/main.rs"), "/foo/src/main.rs");
-        assert_eq!(map_path_prefix(mapping, "abc/def"), "/foo");
+        assert_eq!(map_path_prefix(mapping, "abc/def/src/main.rs"), path_str("/foo/src/main.rs"));
+        assert_eq!(map_path_prefix(mapping, "abc/def"), path_str("/foo"));
     }
 
     // Absolute to relative
     {
-        let mapping = &FilePathMapping::new(vec![("/abc/def".into(), "foo".into())]);
+        let mapping = &FilePathMapping::new(vec![(path("/abc/def"), path("foo"))]);
 
-        assert_eq!(map_path_prefix(mapping, "/abc/def/src/main.rs"), "foo/src/main.rs");
-        assert_eq!(map_path_prefix(mapping, "/abc/def"), "foo");
+        assert_eq!(map_path_prefix(mapping, "/abc/def/src/main.rs"), path_str("foo/src/main.rs"));
+        assert_eq!(map_path_prefix(mapping, "/abc/def"), path_str("foo"));
     }
 
     // Absolute to absolute
     {
-        let mapping = &FilePathMapping::new(vec![("/abc/def".into(), "/foo".into())]);
+        let mapping = &FilePathMapping::new(vec![(path("/abc/def"), path("/foo"))]);
 
-        assert_eq!(map_path_prefix(mapping, "/abc/def/src/main.rs"), "/foo/src/main.rs");
-        assert_eq!(map_path_prefix(mapping, "/abc/def"), "/foo");
+        assert_eq!(map_path_prefix(mapping, "/abc/def/src/main.rs"), path_str("/foo/src/main.rs"));
+        assert_eq!(map_path_prefix(mapping, "/abc/def"), path_str("/foo"));
     }
 }
 
-#[cfg(windows)]
 #[test]
-fn path_prefix_remapping_from_relative2() {
-    // Relative to relative
-    {
-        let mapping = &FilePathMapping::new(vec![("abc\\def".into(), "foo".into())]);
+fn path_prefix_remapping_expand_to_absolute() {
+    // "virtual" working directory is relative path
+    let mapping =
+        &FilePathMapping::new(vec![(path("/foo"), path("FOO")), (path("/bar"), path("BAR"))]);
+    let working_directory = path("/foo");
+    let working_directory = RealFileName::Remapped {
+        local_path: Some(working_directory.clone()),
+        virtual_name: mapping.map_prefix(working_directory).0,
+    };
 
-        assert_eq!(map_path_prefix(mapping, "abc\\def\\src\\main.rs"), "foo\\src\\main.rs");
-        assert_eq!(map_path_prefix(mapping, "abc\\def"), "foo");
-    }
+    assert_eq!(working_directory.remapped_path_if_available(), path("FOO"));
 
-    // Relative to absolute
-    {
-        let mapping = &FilePathMapping::new(vec![("abc\\def".into(), "X:\\foo".into())]);
+    // Unmapped absolute path
+    assert_eq!(
+        mapping.to_embeddable_absolute_path(
+            RealFileName::LocalPath(path("/foo/src/main.rs")),
+            &working_directory
+        ),
+        RealFileName::Remapped { local_path: None, virtual_name: path("FOO/src/main.rs") }
+    );
 
-        assert_eq!(map_path_prefix(mapping, "abc\\def\\src\\main.rs"), "X:\\foo\\src\\main.rs");
-        assert_eq!(map_path_prefix(mapping, "abc\\def"), "X:\\foo");
-    }
+    // Unmapped absolute path with unrelated working directory
+    assert_eq!(
+        mapping.to_embeddable_absolute_path(
+            RealFileName::LocalPath(path("/bar/src/main.rs")),
+            &working_directory
+        ),
+        RealFileName::Remapped { local_path: None, virtual_name: path("BAR/src/main.rs") }
+    );
 
-    // Absolute to relative
-    {
-        let mapping = &FilePathMapping::new(vec![("X:\\abc\\def".into(), "foo".into())]);
+    // Unmapped absolute path that does not match any prefix
+    assert_eq!(
+        mapping.to_embeddable_absolute_path(
+            RealFileName::LocalPath(path("/quux/src/main.rs")),
+            &working_directory
+        ),
+        RealFileName::LocalPath(path("/quux/src/main.rs")),
+    );
 
-        assert_eq!(map_path_prefix(mapping, "X:\\abc\\def\\src\\main.rs"), "foo\\src\\main.rs");
-        assert_eq!(map_path_prefix(mapping, "X:\\abc\\def"), "foo");
-    }
+    // Unmapped relative path
+    assert_eq!(
+        mapping.to_embeddable_absolute_path(
+            RealFileName::LocalPath(path("src/main.rs")),
+            &working_directory
+        ),
+        RealFileName::Remapped { local_path: None, virtual_name: path("FOO/src/main.rs") }
+    );
 
-    // Absolute to absolute
-    {
-        let mapping = &FilePathMapping::new(vec![("X:\\abc\\def".into(), "X:\\foo".into())]);
+    // Unmapped relative path with `./`
+    assert_eq!(
+        mapping.to_embeddable_absolute_path(
+            RealFileName::LocalPath(path("./src/main.rs")),
+            &working_directory
+        ),
+        RealFileName::Remapped { local_path: None, virtual_name: path("FOO/src/main.rs") }
+    );
 
-        assert_eq!(map_path_prefix(mapping, "X:\\abc\\def\\src\\main.rs"), "X:\\foo\\src\\main.rs");
-        assert_eq!(map_path_prefix(mapping, "X:\\abc\\def"), "X:\\foo");
-    }
+    // Unmapped relative path that does not match any prefix
+    assert_eq!(
+        mapping.to_embeddable_absolute_path(
+            RealFileName::LocalPath(path("quux/src/main.rs")),
+            &RealFileName::LocalPath(path("/abc")),
+        ),
+        RealFileName::LocalPath(path("/abc/quux/src/main.rs")),
+    );
+
+    // Already remapped absolute path
+    assert_eq!(
+        mapping.to_embeddable_absolute_path(
+            RealFileName::Remapped {
+                local_path: Some(path("/foo/src/main.rs")),
+                virtual_name: path("FOO/src/main.rs"),
+            },
+            &working_directory
+        ),
+        RealFileName::Remapped { local_path: None, virtual_name: path("FOO/src/main.rs") }
+    );
+
+    // Already remapped absolute path, with unrelated working directory
+    assert_eq!(
+        mapping.to_embeddable_absolute_path(
+            RealFileName::Remapped {
+                local_path: Some(path("/bar/src/main.rs")),
+                virtual_name: path("BAR/src/main.rs"),
+            },
+            &working_directory
+        ),
+        RealFileName::Remapped { local_path: None, virtual_name: path("BAR/src/main.rs") }
+    );
+
+    // Already remapped relative path
+    assert_eq!(
+        mapping.to_embeddable_absolute_path(
+            RealFileName::Remapped { local_path: None, virtual_name: path("XYZ/src/main.rs") },
+            &working_directory
+        ),
+        RealFileName::Remapped { local_path: None, virtual_name: path("XYZ/src/main.rs") }
+    );
 }
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 2cc6eb0..8a6941a 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -125,11 +125,13 @@
     Symbols {
         AcqRel,
         Acquire,
+        AddSubdiagnostic,
         Alignment,
         Any,
         Arc,
         Argument,
         ArgumentV1,
+        ArgumentV1Methods,
         Arguments,
         AsMut,
         AsRef,
@@ -156,6 +158,7 @@
         C,
         CStr,
         CString,
+        Capture,
         Center,
         Clone,
         Continue,
@@ -169,6 +172,7 @@
         Decoder,
         Default,
         Deref,
+        DiagnosticMessage,
         DirBuilder,
         Display,
         DoubleEndedIterator,
@@ -205,6 +209,7 @@
         IntoIterator,
         IoRead,
         IoWrite,
+        IrTyKind,
         Is,
         ItemContext,
         Iterator,
@@ -252,16 +257,20 @@
         RustcEncodable,
         Send,
         SeqCst,
+        SessionDiagnostic,
         SliceIndex,
         Some,
         String,
         StructuralEq,
         StructuralPartialEq,
+        SubdiagnosticMessage,
         Sync,
         Target,
         ToOwned,
         ToString,
         Try,
+        TryCaptureGeneric,
+        TryCapturePrintable,
         TryFrom,
         TryInto,
         Ty,
@@ -271,6 +280,7 @@
         UnsafeArg,
         Vec,
         VecDeque,
+        Wrapper,
         Yield,
         _DECLS,
         _Self,
@@ -353,6 +363,7 @@
         assert_receiver_is_total_eq,
         assert_uninit_valid,
         assert_zero_valid,
+        asserting,
         associated_const_equality,
         associated_consts,
         associated_type_bounds,
@@ -427,6 +438,7 @@
         cfg_panic,
         cfg_sanitize,
         cfg_target_abi,
+        cfg_target_compact,
         cfg_target_feature,
         cfg_target_has_atomic,
         cfg_target_has_atomic_equal_alignment,
@@ -503,6 +515,7 @@
         const_raw_ptr_deref,
         const_raw_ptr_to_usize_cast,
         const_refs_to_cell,
+        const_trait,
         const_trait_bound_opt_out,
         const_trait_impl,
         const_transmute,
@@ -721,6 +734,7 @@
         fundamental,
         future,
         future_trait,
+        gdb_script_file,
         ge,
         gen_future,
         gen_kill,
@@ -729,6 +743,7 @@
         generator_state,
         generators,
         generic_arg_infer,
+        generic_assert,
         generic_associated_types,
         generic_associated_types_extended,
         generic_const_exprs,
@@ -1158,6 +1173,7 @@
         rust_2024,
         rust_2024_preview,
         rust_begin_unwind,
+        rust_cold_cc,
         rust_eh_catch_typeinfo,
         rust_eh_personality,
         rust_eh_register_frames,
@@ -1169,6 +1185,7 @@
         rustc_allow_const_fn_unstable,
         rustc_allow_incoherent_impl,
         rustc_attrs,
+        rustc_box,
         rustc_builtin_macro,
         rustc_capture_analysis,
         rustc_clean,
@@ -1177,7 +1194,6 @@
         rustc_const_unstable,
         rustc_conversion_suggestion,
         rustc_def_path,
-        rustc_deprecated,
         rustc_diagnostic_item,
         rustc_diagnostic_macros,
         rustc_dirty,
@@ -1198,6 +1214,7 @@
         rustc_layout_scalar_valid_range_end,
         rustc_layout_scalar_valid_range_start,
         rustc_legacy_const_generics,
+        rustc_lint_diagnostics,
         rustc_lint_query_instability,
         rustc_macro_transparency,
         rustc_main,
@@ -1375,6 +1392,7 @@
         sym,
         sync,
         t32,
+        target,
         target_abi,
         target_arch,
         target_endian,
@@ -1408,6 +1426,7 @@
         thread_local_macro,
         thumb2,
         thumb_mode: "thumb-mode",
+        tmm_reg,
         todo_macro,
         tool_attributes,
         tool_lints,
@@ -1423,6 +1442,7 @@
         truncf32,
         truncf64,
         try_blocks,
+        try_capture,
         try_from,
         try_into,
         try_trait_v2,
@@ -1430,6 +1450,7 @@
         tuple,
         tuple_from_req,
         tuple_indexing,
+        tuple_variadic,
         two_phase,
         ty,
         type_alias_enum_variants,
@@ -1485,6 +1506,7 @@
         unsized_tuple_coercion,
         unstable,
         untagged_unions,
+        unused_imports,
         unused_qualifications,
         unwind,
         unwind_attributes,
@@ -1620,7 +1642,7 @@
 
 impl PartialEq for Ident {
     fn eq(&self, rhs: &Self) -> bool {
-        self.name == rhs.name && self.span.ctxt() == rhs.span.ctxt()
+        self.name == rhs.name && self.span.eq_ctxt(rhs.span)
     }
 }
 
@@ -1793,8 +1815,8 @@
 }
 
 impl<S: Encoder> Encodable<S> for Symbol {
-    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
-        s.emit_str(self.as_str())
+    fn encode(&self, s: &mut S) {
+        s.emit_str(self.as_str());
     }
 }
 
diff --git a/compiler/rustc_span/src/tests.rs b/compiler/rustc_span/src/tests.rs
index 11edcacc..5b3915c 100644
--- a/compiler/rustc_span/src/tests.rs
+++ b/compiler/rustc_span/src/tests.rs
@@ -5,7 +5,7 @@
     let source = "abcdefghijklm\nabcdefghij\n...".to_owned();
     let sf =
         SourceFile::new(FileName::Anon(0), source, BytePos(3), SourceFileHashAlgorithm::Sha256);
-    assert_eq!(sf.lines.as_slice(), &[BytePos(3), BytePos(17), BytePos(28)]);
+    sf.lines(|lines| assert_eq!(lines, &[BytePos(3), BytePos(17), BytePos(28)]));
 
     assert_eq!(sf.lookup_line(BytePos(0)), None);
     assert_eq!(sf.lookup_line(BytePos(3)), Some(0));
diff --git a/compiler/rustc_symbol_mangling/Cargo.toml b/compiler/rustc_symbol_mangling/Cargo.toml
index b9751f0..d5befa1 100644
--- a/compiler/rustc_symbol_mangling/Cargo.toml
+++ b/compiler/rustc_symbol_mangling/Cargo.toml
@@ -16,5 +16,4 @@
 rustc_hir = { path = "../rustc_hir" }
 rustc_target = { path = "../rustc_target" }
 rustc_data_structures = { path = "../rustc_data_structures" }
-rustc_query_system = { path = "../rustc_query_system" }
 rustc_session = { path = "../rustc_session" }
diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs
index b3773d5..f67b87a 100644
--- a/compiler/rustc_symbol_mangling/src/legacy.rs
+++ b/compiler/rustc_symbol_mangling/src/legacy.rs
@@ -1,7 +1,6 @@
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_hir::def_id::CrateNum;
 use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData};
-use rustc_middle::mir::interpret::{ConstValue, Scalar};
 use rustc_middle::ty::print::{PrettyPrinter, Print, Printer};
 use rustc_middle::ty::subst::{GenericArg, GenericArgKind};
 use rustc_middle::ty::{self, Instance, Ty, TyCtxt, TypeFoldable};
@@ -30,6 +29,7 @@
         match key.disambiguated_data.data {
             DefPathData::TypeNs(_) | DefPathData::ValueNs(_) => {
                 instance_ty = tcx.type_of(ty_def_id);
+                debug!(?instance_ty);
                 break;
             }
             _ => {
@@ -228,9 +228,9 @@
                 self.write_str("[")?;
                 self = self.print_type(ty)?;
                 self.write_str("; ")?;
-                if let Some(size) = size.val().try_to_bits(self.tcx().data_layout.pointer_size) {
+                if let Some(size) = size.kind().try_to_bits(self.tcx().data_layout.pointer_size) {
                     write!(self, "{}", size)?
-                } else if let ty::ConstKind::Param(param) = size.val() {
+                } else if let ty::ConstKind::Param(param) = size.kind() {
                     self = param.print(self)?
                 } else {
                     self.write_str("_")?
@@ -260,11 +260,8 @@
 
     fn print_const(self, ct: ty::Const<'tcx>) -> Result<Self::Const, Self::Error> {
         // only print integers
-        match (ct.val(), ct.ty().kind()) {
-            (
-                ty::ConstKind::Value(ConstValue::Scalar(Scalar::Int(scalar))),
-                ty::Int(_) | ty::Uint(_),
-            ) => {
+        match (ct.kind(), ct.ty().kind()) {
+            (ty::ConstKind::Value(ty::ValTree::Leaf(scalar)), ty::Int(_) | ty::Uint(_)) => {
                 // The `pretty_print_const` formatting depends on -Zverbose
                 // flag, so we cannot reuse it here.
                 let signed = matches!(ct.ty().kind(), ty::Int(_));
diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs
index ee0994c..bed0e81 100644
--- a/compiler/rustc_symbol_mangling/src/lib.rs
+++ b/compiler/rustc_symbol_mangling/src/lib.rs
@@ -89,7 +89,6 @@
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![feature(never_type)]
-#![feature(nll)]
 #![recursion_limit = "256"]
 #![allow(rustc::potential_query_instability)]
 
@@ -156,6 +155,13 @@
     v0::mangle_typeid_for_fnabi(tcx, fn_abi)
 }
 
+pub fn typeid_for_trait_ref<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    trait_ref: ty::PolyExistentialTraitRef<'tcx>,
+) -> String {
+    v0::mangle_typeid_for_trait_ref(tcx, trait_ref)
+}
+
 /// Computes the symbol name for the given instance. This function will call
 /// `compute_instantiating_crate` if it needs to factor the instantiating crate
 /// into the symbol name.
diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs
index dc1946b..1036c5d 100644
--- a/compiler/rustc_symbol_mangling/src/v0.rs
+++ b/compiler/rustc_symbol_mangling/src/v0.rs
@@ -5,7 +5,6 @@
 use rustc_hir::def::CtorKind;
 use rustc_hir::def_id::{CrateNum, DefId};
 use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData};
-use rustc_middle::mir::interpret::ConstValue;
 use rustc_middle::ty::layout::IntegerExt;
 use rustc_middle::ty::print::{Print, Printer};
 use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst};
@@ -95,6 +94,24 @@
     format!("typeid{}", arg_count)
 }
 
+pub(super) fn mangle_typeid_for_trait_ref<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    trait_ref: ty::PolyExistentialTraitRef<'tcx>,
+) -> String {
+    // FIXME(flip1995): See comment in `mangle_typeid_for_fnabi`.
+    let mut cx = &mut SymbolMangler {
+        tcx,
+        start_offset: 0,
+        paths: FxHashMap::default(),
+        types: FxHashMap::default(),
+        consts: FxHashMap::default(),
+        binders: vec![],
+        out: String::new(),
+    };
+    cx = cx.print_def_path(trait_ref.def_id(), &[]).unwrap();
+    std::mem::take(&mut cx.out)
+}
+
 struct BinderLevel {
     /// The range of distances from the root of what's
     /// being printed, to the lifetimes in a binder.
@@ -582,7 +599,7 @@
     fn print_const(mut self, ct: ty::Const<'tcx>) -> Result<Self::Const, Self::Error> {
         // We only mangle a typed value if the const can be evaluated.
         let ct = ct.eval(self.tcx, ty::ParamEnv::reveal_all());
-        match ct.val() {
+        match ct.kind() {
             ty::ConstKind::Value(_) => {}
 
             // Placeholders (should be demangled as `_`).
@@ -604,16 +621,18 @@
         if let Some(&i) = self.consts.get(&ct) {
             return self.print_backref(i);
         }
+
         let start = self.out.len();
+        let ty = ct.ty();
 
-        match ct.ty().kind() {
+        match ty.kind() {
             ty::Uint(_) | ty::Int(_) | ty::Bool | ty::Char => {
-                self = ct.ty().print(self)?;
+                self = ty.print(self)?;
 
-                let mut bits = ct.eval_bits(self.tcx, ty::ParamEnv::reveal_all(), ct.ty());
+                let mut bits = ct.eval_bits(self.tcx, ty::ParamEnv::reveal_all(), ty);
 
                 // Negative integer values are mangled using `n` as a "sign prefix".
-                if let ty::Int(ity) = ct.ty().kind() {
+                if let ty::Int(ity) = ty.kind() {
                     let val =
                         Integer::from_int_ty(&self.tcx, *ity).size().sign_extend(bits) as i128;
                     if val < 0 {
@@ -625,46 +644,57 @@
                 let _ = write!(self.out, "{:x}_", bits);
             }
 
-            // HACK(eddyb) because `ty::Const` only supports sized values (for now),
-            // we can't use `deref_const` + supporting `str`, we have to specially
-            // handle `&str` and include both `&` ("R") and `str` ("e") prefixes.
-            ty::Ref(_, ty, hir::Mutability::Not) if *ty == self.tcx.types.str_ => {
-                self.push("R");
-                match ct.val() {
-                    ty::ConstKind::Value(ConstValue::Slice { data, start, end }) => {
-                        // NOTE(eddyb) the following comment was kept from `ty::print::pretty`:
-                        // The `inspect` here is okay since we checked the bounds, and there are no
-                        // relocations (we have an active `str` reference here). We don't use this
-                        // result to affect interpreter execution.
-                        let slice = data
-                            .inner()
-                            .inspect_with_uninit_and_ptr_outside_interpreter(start..end);
-                        let s = std::str::from_utf8(slice).expect("non utf8 str from miri");
-
-                        self.push("e");
-                        // FIXME(eddyb) use a specialized hex-encoding loop.
-                        for byte in s.bytes() {
-                            let _ = write!(self.out, "{:02x}", byte);
-                        }
-                        self.push("_");
-                    }
-
-                    _ => {
-                        bug!("symbol_names: unsupported `&str` constant: {:?}", ct);
-                    }
-                }
-            }
-
-            ty::Ref(_, _, mutbl) => {
+            // FIXME(valtrees): Remove the special case for `str`
+            // here and fully support unsized constants.
+            ty::Ref(_, inner_ty, mutbl) => {
                 self.push(match mutbl {
                     hir::Mutability::Not => "R",
                     hir::Mutability::Mut => "Q",
                 });
-                self = self.tcx.deref_const(ty::ParamEnv::reveal_all().and(ct)).print(self)?;
+
+                match inner_ty.kind() {
+                    ty::Str if *mutbl == hir::Mutability::Not => {
+                        match ct.kind() {
+                            ty::ConstKind::Value(valtree) => {
+                                let slice =
+                                    valtree.try_to_raw_bytes(self.tcx(), ty).unwrap_or_else(|| {
+                                        bug!(
+                                        "expected to get raw bytes from valtree {:?} for type {:}",
+                                        valtree, ty
+                                    )
+                                    });
+                                let s = std::str::from_utf8(slice).expect("non utf8 str from miri");
+
+                                self.push("e");
+
+                                // FIXME(eddyb) use a specialized hex-encoding loop.
+                                for byte in s.bytes() {
+                                    let _ = write!(self.out, "{:02x}", byte);
+                                }
+
+                                self.push("_");
+                            }
+
+                            _ => {
+                                bug!("symbol_names: unsupported `&str` constant: {:?}", ct);
+                            }
+                        }
+                    }
+                    _ => {
+                        let pointee_ty = ct
+                            .ty()
+                            .builtin_deref(true)
+                            .expect("tried to dereference on non-ptr type")
+                            .ty;
+                        let dereferenced_const =
+                            self.tcx.mk_const(ty::ConstS { kind: ct.kind(), ty: pointee_ty });
+                        self = dereferenced_const.print(self)?;
+                    }
+                }
             }
 
-            ty::Array(..) | ty::Tuple(..) | ty::Adt(..) => {
-                let contents = self.tcx.destructure_const(ty::ParamEnv::reveal_all().and(ct));
+            ty::Array(..) | ty::Tuple(..) | ty::Adt(..) | ty::Slice(_) => {
+                let contents = self.tcx.destructure_const(ct);
                 let fields = contents.fields.iter().copied();
 
                 let print_field_list = |mut this: Self| {
@@ -676,7 +706,7 @@
                 };
 
                 match *ct.ty().kind() {
-                    ty::Array(..) => {
+                    ty::Array(..) | ty::Slice(_) => {
                         self.push("A");
                         self = print_field_list(self)?;
                     }
@@ -723,7 +753,6 @@
                     _ => unreachable!(),
                 }
             }
-
             _ => {
                 bug!("symbol_names: unsupported constant of type `{}` ({:?})", ct.ty(), ct);
             }
diff --git a/compiler/rustc_target/Cargo.toml b/compiler/rustc_target/Cargo.toml
index 925813e..162376a 100644
--- a/compiler/rustc_target/Cargo.toml
+++ b/compiler/rustc_target/Cargo.toml
@@ -6,6 +6,7 @@
 [dependencies]
 bitflags = "1.2.1"
 tracing = "0.1"
+serde_json = "1.0.59"
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_macros = { path = "../rustc_macros" }
 rustc_serialize = { path = "../rustc_serialize" }
diff --git a/compiler/rustc_target/src/abi/call/mod.rs b/compiler/rustc_target/src/abi/call/mod.rs
index afce10f..ca1d130 100644
--- a/compiler/rustc_target/src/abi/call/mod.rs
+++ b/compiler/rustc_target/src/abi/call/mod.rs
@@ -580,6 +580,11 @@
     C,
     Rust,
 
+    /// For things unlikely to be called, where smaller caller codegen is
+    /// preferred over raw speed.
+    /// Stronger than just `#[cold]` because `fn` pointers might be incompatible.
+    RustCold,
+
     // Target-specific calling conventions.
     ArmAapcs,
     CCmseNonSecureCall,
diff --git a/compiler/rustc_target/src/abi/mod.rs b/compiler/rustc_target/src/abi/mod.rs
index a2cd3c4..d1eafd6 100644
--- a/compiler/rustc_target/src/abi/mod.rs
+++ b/compiler/rustc_target/src/abi/mod.rs
@@ -1,6 +1,7 @@
 pub use Integer::*;
 pub use Primitive::*;
 
+use crate::json::{Json, ToJson};
 use crate::spec::Target;
 
 use std::convert::{TryFrom, TryInto};
@@ -13,7 +14,6 @@
 use rustc_data_structures::intern::Interned;
 use rustc_index::vec::{Idx, IndexVec};
 use rustc_macros::HashStable_Generic;
-use rustc_serialize::json::{Json, ToJson};
 
 pub mod call;
 
@@ -166,7 +166,8 @@
             ));
         }
 
-        if dl.pointer_size.bits() != target.pointer_width.into() {
+        let target_pointer_width: u64 = target.pointer_width.into();
+        if dl.pointer_size.bits() != target_pointer_width {
             return Err(format!(
                 "inconsistent target specification: \"data-layout\" claims \
                  pointers are {}-bit, while \"target-pointer-width\" is `{}`",
@@ -574,7 +575,7 @@
 }
 
 /// A pair of alignments, ABI-mandated and preferred.
-#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Encodable, Decodable)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
 #[derive(HashStable_Generic)]
 pub struct AbiAndPrefAlign {
     pub abi: Align,
@@ -746,6 +747,11 @@
     pub fn is_int(self) -> bool {
         matches!(self, Int(..))
     }
+
+    #[inline]
+    pub fn is_ptr(self) -> bool {
+        matches!(self, Pointer)
+    }
 }
 
 /// Inclusive wrap-around range of valid values, that is, if
@@ -894,6 +900,15 @@
             Scalar::Union { .. } => true,
         }
     }
+
+    /// Returns `true` if this type can be left uninit.
+    #[inline]
+    pub fn is_uninit_valid(&self) -> bool {
+        match *self {
+            Scalar::Initialized { .. } => false,
+            Scalar::Union { .. } => true,
+        }
+    }
 }
 
 /// Describes how the fields of a type are located in memory.
@@ -1355,6 +1370,14 @@
     pub address_space: AddressSpace,
 }
 
+/// Used in `might_permit_raw_init` to indicate the kind of initialisation
+/// that is checked to be valid
+#[derive(Copy, Clone, Debug)]
+pub enum InitKind {
+    Zero,
+    Uninit,
+}
+
 /// Trait that needs to be implemented by the higher-level type representation
 /// (e.g. `rustc_middle::ty::Ty`), to provide `rustc_target::abi` functionality.
 pub trait TyAbiInterface<'a, C>: Sized {
@@ -1461,26 +1484,37 @@
 
     /// Determines if this type permits "raw" initialization by just transmuting some
     /// memory into an instance of `T`.
-    /// `zero` indicates if the memory is zero-initialized, or alternatively
-    /// left entirely uninitialized.
+    ///
+    /// `init_kind` indicates if the memory is zero-initialized or left uninitialized.
+    ///
+    /// `strict` is an opt-in debugging flag added in #97323 that enables more checks.
+    ///
     /// This is conservative: in doubt, it will answer `true`.
     ///
     /// FIXME: Once we removed all the conservatism, we could alternatively
     /// create an all-0/all-undef constant and run the const value validator to see if
     /// this is a valid value for the given type.
-    pub fn might_permit_raw_init<C>(self, cx: &C, zero: bool) -> bool
+    pub fn might_permit_raw_init<C>(self, cx: &C, init_kind: InitKind, strict: bool) -> bool
     where
         Self: Copy,
         Ty: TyAbiInterface<'a, C>,
         C: HasDataLayout,
     {
         let scalar_allows_raw_init = move |s: Scalar| -> bool {
-            if zero {
-                // The range must contain 0.
-                s.valid_range(cx).contains(0)
-            } else {
-                // The range must include all values.
-                s.is_always_valid(cx)
+            match init_kind {
+                InitKind::Zero => {
+                    // The range must contain 0.
+                    s.valid_range(cx).contains(0)
+                }
+                InitKind::Uninit => {
+                    if strict {
+                        // The type must be allowed to be uninit (which means "is a union").
+                        s.is_uninit_valid()
+                    } else {
+                        // The range must include all values.
+                        s.is_always_valid(cx)
+                    }
+                }
             }
         };
 
@@ -1500,12 +1534,19 @@
         // If we have not found an error yet, we need to recursively descend into fields.
         match &self.fields {
             FieldsShape::Primitive | FieldsShape::Union { .. } => {}
-            FieldsShape::Array { .. } => {
-                // FIXME(#66151): For now, we are conservative and do not check arrays.
+            FieldsShape::Array { count, .. } => {
+                // FIXME(#66151): For now, we are conservative and do not check arrays by default.
+                if strict
+                    && *count > 0
+                    && !self.field(cx, 0).might_permit_raw_init(cx, init_kind, strict)
+                {
+                    // Found non empty array with a type that is unhappy about this kind of initialization
+                    return false;
+                }
             }
             FieldsShape::Arbitrary { offsets, .. } => {
                 for idx in 0..offsets.len() {
-                    if !self.field(cx, idx).might_permit_raw_init(cx, zero) {
+                    if !self.field(cx, idx).might_permit_raw_init(cx, init_kind, strict) {
                         // We found a field that is unhappy with this kind of initialization.
                         return false;
                     }
diff --git a/compiler/rustc_target/src/asm/aarch64.rs b/compiler/rustc_target/src/asm/aarch64.rs
index fba8cc6..2584204 100644
--- a/compiler/rustc_target/src/asm/aarch64.rs
+++ b/compiler/rustc_target/src/asm/aarch64.rs
@@ -74,7 +74,7 @@
 }
 
 pub fn target_reserves_x18(target: &Target) -> bool {
-    target.os == "android" || target.is_like_fuchsia || target.is_like_osx || target.is_like_windows
+    target.os == "android" || target.os == "fuchsia" || target.is_like_osx || target.is_like_windows
 }
 
 fn reserved_x18(
diff --git a/compiler/rustc_target/src/asm/mod.rs b/compiler/rustc_target/src/asm/mod.rs
index 6bc807c..df8ccc4 100644
--- a/compiler/rustc_target/src/asm/mod.rs
+++ b/compiler/rustc_target/src/asm/mod.rs
@@ -912,6 +912,7 @@
 
                     mm0, mm1, mm2, mm3, mm4, mm5, mm6, mm7,
                     st0, st1, st2, st3, st4, st5, st6, st7,
+                    tmm0, tmm1, tmm2, tmm3, tmm4, tmm5, tmm6, tmm7,
                 }
             },
             InlineAsmClobberAbi::X86_64Win => clobbered_regs! {
@@ -931,6 +932,7 @@
 
                     mm0, mm1, mm2, mm3, mm4, mm5, mm6, mm7,
                     st0, st1, st2, st3, st4, st5, st6, st7,
+                    tmm0, tmm1, tmm2, tmm3, tmm4, tmm5, tmm6, tmm7,
                 }
             },
             InlineAsmClobberAbi::AArch64 => clobbered_regs! {
diff --git a/compiler/rustc_target/src/asm/x86.rs b/compiler/rustc_target/src/asm/x86.rs
index 854674c..e35035f 100644
--- a/compiler/rustc_target/src/asm/x86.rs
+++ b/compiler/rustc_target/src/asm/x86.rs
@@ -17,6 +17,7 @@
         kreg0,
         mmx_reg,
         x87_reg,
+        tmm_reg,
     }
 }
 
@@ -41,6 +42,7 @@
             Self::xmm_reg | Self::ymm_reg | Self::zmm_reg => &['x', 'y', 'z'],
             Self::kreg | Self::kreg0 => &[],
             Self::mmx_reg | Self::x87_reg => &[],
+            Self::tmm_reg => &[],
         }
     }
 
@@ -80,6 +82,7 @@
             },
             Self::kreg | Self::kreg0 => None,
             Self::mmx_reg | Self::x87_reg => None,
+            Self::tmm_reg => None,
         }
     }
 
@@ -98,6 +101,7 @@
             Self::zmm_reg => Some(('z', "zmm0")),
             Self::kreg | Self::kreg0 => None,
             Self::mmx_reg | Self::x87_reg => None,
+            Self::tmm_reg => None,
         }
     }
 
@@ -135,6 +139,7 @@
             },
             Self::kreg0 => &[],
             Self::mmx_reg | Self::x87_reg => &[],
+            Self::tmm_reg => &[],
         }
     }
 }
@@ -320,6 +325,14 @@
         st5: x87_reg = ["st(5)"],
         st6: x87_reg = ["st(6)"],
         st7: x87_reg = ["st(7)"],
+        tmm0: tmm_reg = ["tmm0"] % x86_64_only,
+        tmm1: tmm_reg = ["tmm1"] % x86_64_only,
+        tmm2: tmm_reg = ["tmm2"] % x86_64_only,
+        tmm3: tmm_reg = ["tmm3"] % x86_64_only,
+        tmm4: tmm_reg = ["tmm4"] % x86_64_only,
+        tmm5: tmm_reg = ["tmm5"] % x86_64_only,
+        tmm6: tmm_reg = ["tmm6"] % x86_64_only,
+        tmm7: tmm_reg = ["tmm7"] % x86_64_only,
         #error = ["bp", "bpl", "ebp", "rbp"] =>
             "the frame pointer cannot be used as an operand for inline asm",
         #error = ["sp", "spl", "esp", "rsp"] =>
diff --git a/compiler/rustc_target/src/json.rs b/compiler/rustc_target/src/json.rs
new file mode 100644
index 0000000..b5d9263
--- /dev/null
+++ b/compiler/rustc_target/src/json.rs
@@ -0,0 +1,91 @@
+use std::borrow::Cow;
+use std::collections::BTreeMap;
+
+pub use serde_json::Value as Json;
+use serde_json::{Map, Number};
+
+pub trait ToJson {
+    fn to_json(&self) -> Json;
+}
+
+impl ToJson for Json {
+    fn to_json(&self) -> Json {
+        self.clone()
+    }
+}
+
+macro_rules! to_json_impl_num {
+    ($($t:ty), +) => (
+        $(impl ToJson for $t {
+            fn to_json(&self) -> Json {
+                Json::Number(Number::from(*self))
+            }
+        })+
+    )
+}
+
+to_json_impl_num! { isize, i8, i16, i32, i64, usize, u8, u16, u32, u64 }
+
+impl ToJson for bool {
+    fn to_json(&self) -> Json {
+        Json::Bool(*self)
+    }
+}
+
+impl ToJson for str {
+    fn to_json(&self) -> Json {
+        Json::String(self.to_owned())
+    }
+}
+
+impl ToJson for String {
+    fn to_json(&self) -> Json {
+        Json::String(self.to_owned())
+    }
+}
+
+impl<'a> ToJson for Cow<'a, str> {
+    fn to_json(&self) -> Json {
+        Json::String(self.to_string())
+    }
+}
+
+impl<A: ToJson> ToJson for [A] {
+    fn to_json(&self) -> Json {
+        Json::Array(self.iter().map(|elt| elt.to_json()).collect())
+    }
+}
+
+impl<A: ToJson> ToJson for Vec<A> {
+    fn to_json(&self) -> Json {
+        Json::Array(self.iter().map(|elt| elt.to_json()).collect())
+    }
+}
+
+impl<'a, A: ToJson> ToJson for Cow<'a, [A]>
+where
+    [A]: ToOwned,
+{
+    fn to_json(&self) -> Json {
+        Json::Array(self.iter().map(|elt| elt.to_json()).collect())
+    }
+}
+
+impl<T: ToString, A: ToJson> ToJson for BTreeMap<T, A> {
+    fn to_json(&self) -> Json {
+        let mut d = Map::new();
+        for (key, value) in self {
+            d.insert(key.to_string(), value.to_json());
+        }
+        Json::Object(d)
+    }
+}
+
+impl<A: ToJson> ToJson for Option<A> {
+    fn to_json(&self) -> Json {
+        match *self {
+            None => Json::Null,
+            Some(ref value) => value.to_json(),
+        }
+    }
+}
diff --git a/compiler/rustc_target/src/lib.rs b/compiler/rustc_target/src/lib.rs
index 4dc6af1..a8ddcc9 100644
--- a/compiler/rustc_target/src/lib.rs
+++ b/compiler/rustc_target/src/lib.rs
@@ -13,7 +13,6 @@
 #![feature(let_else)]
 #![feature(min_specialization)]
 #![feature(never_type)]
-#![feature(nll)]
 #![feature(rustc_attrs)]
 #![feature(step_trait)]
 
@@ -28,6 +27,7 @@
 
 pub mod abi;
 pub mod asm;
+pub mod json;
 pub mod spec;
 
 #[cfg(test)]
diff --git a/compiler/rustc_target/src/spec/aarch64_apple_watchos_sim.rs b/compiler/rustc_target/src/spec/aarch64_apple_watchos_sim.rs
new file mode 100644
index 0000000..3059f42
--- /dev/null
+++ b/compiler/rustc_target/src/spec/aarch64_apple_watchos_sim.rs
@@ -0,0 +1,38 @@
+use super::apple_sdk_base::{opts, Arch};
+use crate::spec::{FramePointer, Target, TargetOptions};
+
+pub fn target() -> Target {
+    let base = opts("watchos", Arch::Arm64_sim);
+
+    // Clang automatically chooses a more specific target based on
+    // WATCHOS_DEPLOYMENT_TARGET.
+    // This is required for the simulator target to pick the right
+    // MACH-O commands, so we do too.
+    let arch = "arm64";
+    let llvm_target = super::apple_base::watchos_sim_llvm_target(arch);
+
+    Target {
+        llvm_target: llvm_target.into(),
+        pointer_width: 64,
+        data_layout: "e-m:o-i64:64-i128:128-n32:64-S128".into(),
+        arch: "aarch64".into(),
+        options: TargetOptions {
+            features: "+neon,+fp-armv8,+apple-a7".into(),
+            max_atomic_width: Some(128),
+            forces_embed_bitcode: true,
+            frame_pointer: FramePointer::NonLeaf,
+            // Taken from a clang build on Xcode 11.4.1.
+            // These arguments are not actually invoked - they just have
+            // to look right to pass App Store validation.
+            bitcode_llvm_cmdline: "-triple\0\
+                arm64-apple-watchos5.0-simulator\0\
+                -emit-obj\0\
+                -disable-llvm-passes\0\
+                -target-abi\0\
+                darwinpcs\0\
+                -Os\0"
+                .into(),
+            ..base
+        },
+    }
+}
diff --git a/compiler/rustc_target/src/spec/abi.rs b/compiler/rustc_target/src/spec/abi.rs
index d9e571c..337554d 100644
--- a/compiler/rustc_target/src/spec/abi.rs
+++ b/compiler/rustc_target/src/spec/abi.rs
@@ -35,6 +35,7 @@
     RustCall,
     PlatformIntrinsic,
     Unadjusted,
+    RustCold,
 }
 
 #[derive(Copy, Clone)]
@@ -81,6 +82,7 @@
     AbiData { abi: Abi::RustCall, name: "rust-call" },
     AbiData { abi: Abi::PlatformIntrinsic, name: "platform-intrinsic" },
     AbiData { abi: Abi::Unadjusted, name: "unadjusted" },
+    AbiData { abi: Abi::RustCold, name: "rust-cold" },
 ];
 
 /// Returns the ABI with the given name (if any).
@@ -139,6 +141,7 @@
             RustCall => 31,
             PlatformIntrinsic => 32,
             Unadjusted => 33,
+            RustCold => 34,
         };
         debug_assert!(
             AbiDatas
diff --git a/compiler/rustc_target/src/spec/apple_base.rs b/compiler/rustc_target/src/spec/apple_base.rs
index 238d3f8..e8460a5 100644
--- a/compiler/rustc_target/src/spec/apple_base.rs
+++ b/compiler/rustc_target/src/spec/apple_base.rs
@@ -114,3 +114,12 @@
     let (major, minor) = ios_deployment_target();
     format!("{}-apple-ios{}.{}.0-simulator", arch, major, minor)
 }
+
+fn watchos_deployment_target() -> (u32, u32) {
+    deployment_target("WATCHOS_DEPLOYMENT_TARGET").unwrap_or((5, 0))
+}
+
+pub fn watchos_sim_llvm_target(arch: &str) -> String {
+    let (major, minor) = watchos_deployment_target();
+    format!("{}-apple-watchos{}.{}.0-simulator", arch, major, minor)
+}
diff --git a/compiler/rustc_target/src/spec/apple_sdk_base.rs b/compiler/rustc_target/src/spec/apple_sdk_base.rs
index e2d0895..ecb6cbd 100644
--- a/compiler/rustc_target/src/spec/apple_sdk_base.rs
+++ b/compiler/rustc_target/src/spec/apple_sdk_base.rs
@@ -6,8 +6,10 @@
 #[derive(Copy, Clone)]
 pub enum Arch {
     Armv7,
+    Armv7k,
     Armv7s,
     Arm64,
+    Arm64_32,
     I386,
     X86_64,
     X86_64_macabi,
@@ -17,7 +19,7 @@
 
 fn target_abi(arch: Arch) -> &'static str {
     match arch {
-        Armv7 | Armv7s | Arm64 | I386 | X86_64 => "",
+        Armv7 | Armv7k | Armv7s | Arm64 | Arm64_32 | I386 | X86_64 => "",
         X86_64_macabi | Arm64_macabi => "macabi",
         Arm64_sim => "sim",
     }
@@ -26,8 +28,10 @@
 fn target_cpu(arch: Arch) -> &'static str {
     match arch {
         Armv7 => "cortex-a8", // iOS7 is supported on iPhone 4 and higher
+        Armv7k => "cortex-a8",
         Armv7s => "cortex-a9",
         Arm64 => "apple-a7",
+        Arm64_32 => "apple-s4",
         I386 => "yonah",
         X86_64 => "core2",
         X86_64_macabi => "core2",
@@ -38,7 +42,7 @@
 
 fn link_env_remove(arch: Arch) -> Cow<'static, [Cow<'static, str>]> {
     match arch {
-        Armv7 | Armv7s | Arm64 | I386 | X86_64 | Arm64_sim => {
+        Armv7 | Armv7k | Armv7s | Arm64 | Arm64_32 | I386 | X86_64 | Arm64_sim => {
             cvs!["MACOSX_DEPLOYMENT_TARGET"]
         }
         X86_64_macabi | Arm64_macabi => cvs!["IPHONEOS_DEPLOYMENT_TARGET"],
diff --git a/compiler/rustc_target/src/spec/arm64_32_apple_watchos.rs b/compiler/rustc_target/src/spec/arm64_32_apple_watchos.rs
new file mode 100644
index 0000000..7b23fe1
--- /dev/null
+++ b/compiler/rustc_target/src/spec/arm64_32_apple_watchos.rs
@@ -0,0 +1,28 @@
+use super::apple_sdk_base::{opts, Arch};
+use crate::spec::{Target, TargetOptions};
+
+pub fn target() -> Target {
+    let base = opts("watchos", Arch::Arm64_32);
+    Target {
+        llvm_target: "arm64_32-apple-watchos".into(),
+        pointer_width: 32,
+        data_layout: "e-m:o-p:32:32-i64:64-i128:128-n32:64-S128".into(),
+        arch: "aarch64".into(),
+        options: TargetOptions {
+            features: "+neon,+fp-armv8,+apple-a7".into(),
+            max_atomic_width: Some(64),
+            forces_embed_bitcode: true,
+            // These arguments are not actually invoked - they just have
+            // to look right to pass App Store validation.
+            bitcode_llvm_cmdline: "-triple\0\
+                arm64_32-apple-watchos5.0.0\0\
+                -emit-obj\0\
+                -disable-llvm-passes\0\
+                -target-abi\0\
+                darwinpcs\0\
+                -Os\0"
+                .into(),
+            ..base
+        },
+    }
+}
diff --git a/compiler/rustc_target/src/spec/armv6k_nintendo_3ds.rs b/compiler/rustc_target/src/spec/armv6k_nintendo_3ds.rs
index ffcd1a3..67df73f 100644
--- a/compiler/rustc_target/src/spec/armv6k_nintendo_3ds.rs
+++ b/compiler/rustc_target/src/spec/armv6k_nintendo_3ds.rs
@@ -37,7 +37,8 @@
             pre_link_args,
             exe_suffix: ".elf".into(),
             no_default_libraries: false,
-            has_thread_local: true,
+            // There are some issues in debug builds with this enabled in certain programs.
+            has_thread_local: false,
             ..Default::default()
         },
     }
diff --git a/compiler/rustc_target/src/spec/armv7k_apple_watchos.rs b/compiler/rustc_target/src/spec/armv7k_apple_watchos.rs
new file mode 100644
index 0000000..af5d1c2
--- /dev/null
+++ b/compiler/rustc_target/src/spec/armv7k_apple_watchos.rs
@@ -0,0 +1,28 @@
+use super::apple_sdk_base::{opts, Arch};
+use crate::spec::{Target, TargetOptions};
+
+pub fn target() -> Target {
+    let base = opts("watchos", Arch::Armv7k);
+    Target {
+        llvm_target: "armv7k-apple-watchos".into(),
+        pointer_width: 32,
+        data_layout: "e-m:o-p:32:32-Fi8-i64:64-a:0:32-n32-S128".into(),
+        arch: "arm".into(),
+        options: TargetOptions {
+            features: "+v7,+vfp4,+neon".into(),
+            max_atomic_width: Some(64),
+            forces_embed_bitcode: true,
+            // These arguments are not actually invoked - they just have
+            // to look right to pass App Store validation.
+            bitcode_llvm_cmdline: "-triple\0\
+                armv7k-apple-watchos3.0.0\0\
+                -emit-obj\0\
+                -disable-llvm-passes\0\
+                -target-abi\0\
+                darwinpcs\0\
+                -Os\0"
+                .into(),
+            ..base
+        },
+    }
+}
diff --git a/compiler/rustc_target/src/spec/asmjs_unknown_emscripten.rs b/compiler/rustc_target/src/spec/asmjs_unknown_emscripten.rs
index a90c7b7..269bf8b 100644
--- a/compiler/rustc_target/src/spec/asmjs_unknown_emscripten.rs
+++ b/compiler/rustc_target/src/spec/asmjs_unknown_emscripten.rs
@@ -2,10 +2,10 @@
 
 pub fn target() -> Target {
     let mut target = wasm32_unknown_emscripten::target();
-    target
-        .post_link_args
-        .entry(LinkerFlavor::Em)
-        .or_default()
-        .extend(vec!["-s".into(), "WASM=0".into()]);
+    target.post_link_args.entry(LinkerFlavor::Em).or_default().extend(vec![
+        "-sWASM=0".into(),
+        "--memory-init-file".into(),
+        "0".into(),
+    ]);
     target
 }
diff --git a/compiler/rustc_target/src/spec/crt_objects.rs b/compiler/rustc_target/src/spec/crt_objects.rs
index 51f392a..52ac362 100644
--- a/compiler/rustc_target/src/spec/crt_objects.rs
+++ b/compiler/rustc_target/src/spec/crt_objects.rs
@@ -40,8 +40,8 @@
 //! but not gcc's. As a result rustc cannot link with C++ static libraries (#36710)
 //! when linking in self-contained mode.
 
+use crate::json::{Json, ToJson};
 use crate::spec::LinkOutputKind;
-use rustc_serialize::json::{Json, ToJson};
 use std::borrow::Cow;
 use std::collections::BTreeMap;
 use std::str::FromStr;
diff --git a/compiler/rustc_target/src/spec/fuchsia_base.rs b/compiler/rustc_target/src/spec/fuchsia_base.rs
index 04e30ff..b64875e 100644
--- a/compiler/rustc_target/src/spec/fuchsia_base.rs
+++ b/compiler/rustc_target/src/spec/fuchsia_base.rs
@@ -28,7 +28,6 @@
         dynamic_linking: true,
         executables: true,
         families: cvs!["unix"],
-        is_like_fuchsia: true,
         pre_link_args,
         pre_link_objects: crt_objects::new(&[
             (LinkOutputKind::DynamicNoPicExe, &["Scrt1.o"]),
diff --git a/compiler/rustc_target/src/spec/mipsel_sony_psp.rs b/compiler/rustc_target/src/spec/mipsel_sony_psp.rs
index 45966b9..03e0934 100644
--- a/compiler/rustc_target/src/spec/mipsel_sony_psp.rs
+++ b/compiler/rustc_target/src/spec/mipsel_sony_psp.rs
@@ -6,7 +6,8 @@
 
 pub fn target() -> Target {
     let mut pre_link_args = LinkArgs::new();
-    pre_link_args.insert(LinkerFlavor::Lld(LldFlavor::Ld), vec!["--emit-relocs".into()]);
+    pre_link_args
+        .insert(LinkerFlavor::Lld(LldFlavor::Ld), vec!["--emit-relocs".into(), "--nmagic".into()]);
 
     Target {
         llvm_target: "mipsel-sony-psp".into(),
diff --git a/compiler/rustc_target/src/spec/mipsel_sony_psp_linker_script.ld b/compiler/rustc_target/src/spec/mipsel_sony_psp_linker_script.ld
index 1bd436d..9eb35ad 100644
--- a/compiler/rustc_target/src/spec/mipsel_sony_psp_linker_script.ld
+++ b/compiler/rustc_target/src/spec/mipsel_sony_psp_linker_script.ld
@@ -7,14 +7,18 @@
   /* Sort stubs for convenient ordering */
   .sceStub.text : { *(.sceStub.text) *(SORT(.sceStub.text.*)) }
 
+  /* PSP import library stub sections. Bundles together `.lib.stub.entry.*`
+   * sections for better `--gc-sections` support. */
+  .lib.stub.top : { *(.lib.stub.top) }
+  .lib.stub :     { *(.lib.stub) *(.lib.stub.entry.*) }
+  .lib.stub.btm : { *(.lib.stub.btm) }
+
   /* Keep these sections around, even though they may appear unused to the linker */
   .lib.ent.top :  { KEEP(*(.lib.ent.top)) }
   .lib.ent :      { KEEP(*(.lib.ent)) }
   .lib.ent.btm :  { KEEP(*(.lib.ent.btm)) }
-  .lib.stub.top : { KEEP(*(.lib.stub.top)) }
-  .lib.stub :     { KEEP(*(.lib.stub)) }
-  .lib.stub.btm : { KEEP(*(.lib.stub.btm)) }
-  .eh_frame_hdr : { KEEP(*(.eh_frame_hdr)) }
+
+  .eh_frame_hdr : { *(.eh_frame_hdr) }
 
   /* Add symbols for LLVM's libunwind */
   __eh_frame_hdr_start = SIZEOF(.eh_frame_hdr) > 0 ? ADDR(.eh_frame_hdr) : 0;
@@ -27,8 +31,15 @@
   }
 
   /* These are explicitly listed to avoid being merged into .rodata */
-  .rodata.sceResident : { *(.rodata.sceResident) }
+  .rodata.sceResident : { *(.rodata.sceResident) *(.rodata.sceResident.*) }
   .rodata.sceModuleInfo : { *(.rodata.sceModuleInfo) }
   /* Sort NIDs for convenient ordering */
   .rodata.sceNid : { *(.rodata.sceNid) *(SORT(.rodata.sceNid.*)) }
+
+  .rodata : { *(.rodata .rodata.*) }
+  .data : { *(.data .data.*) }
+  .gcc_except_table : { *(.gcc_except_table .gcc_except_table.*) }
+  .bss : { *(.bss .bss.*) }
+
+  /DISCARD/ : { *(.rel.sceStub.text .MIPS.abiflags .reginfo) }
 }
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index 832eeec..da0589c 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -35,14 +35,17 @@
 //! to the list specified by the target, rather than replace.
 
 use crate::abi::Endian;
+use crate::json::{Json, ToJson};
 use crate::spec::abi::{lookup as lookup_abi, Abi};
 use crate::spec::crt_objects::{CrtObjects, CrtObjectsFallback};
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
-use rustc_serialize::json::{Json, ToJson};
+use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
 use rustc_span::symbol::{sym, Symbol};
+use serde_json::Value;
 use std::borrow::Cow;
 use std::collections::BTreeMap;
 use std::convert::TryFrom;
+use std::hash::{Hash, Hasher};
 use std::iter::FromIterator;
 use std::ops::{Deref, DerefMut};
 use std::path::{Path, PathBuf};
@@ -108,6 +111,15 @@
 }
 
 impl LldFlavor {
+    pub fn as_str(&self) -> &'static str {
+        match self {
+            LldFlavor::Wasm => "wasm",
+            LldFlavor::Ld64 => "darwin",
+            LldFlavor::Ld => "gnu",
+            LldFlavor::Link => "link",
+        }
+    }
+
     fn from_str(s: &str) -> Option<Self> {
         Some(match s {
             "darwin" => LldFlavor::Ld64,
@@ -121,13 +133,7 @@
 
 impl ToJson for LldFlavor {
     fn to_json(&self) -> Json {
-        match *self {
-            LldFlavor::Ld64 => "darwin",
-            LldFlavor::Ld => "gnu",
-            LldFlavor::Link => "link",
-            LldFlavor::Wasm => "wasm",
-        }
-        .to_json()
+        self.as_str().to_json()
     }
 }
 
@@ -208,7 +214,7 @@
     }
 }
 
-#[derive(Clone, Copy, Debug, PartialEq, Hash, Encodable, Decodable)]
+#[derive(Clone, Copy, Debug, PartialEq, Hash)]
 pub enum RelroLevel {
     Full,
     Partial,
@@ -252,7 +258,7 @@
     }
 }
 
-#[derive(Clone, Copy, Debug, PartialEq, Hash, Encodable, Decodable)]
+#[derive(Clone, Copy, Debug, PartialEq, Hash)]
 pub enum MergeFunctions {
     Disabled,
     Trampolines,
@@ -545,7 +551,7 @@
         let object = json.as_object().ok_or_else(|| "expected a JSON object")?;
         let kind = object
             .get("kind")
-            .and_then(|o| o.as_string())
+            .and_then(|o| o.as_str())
             .ok_or_else(|| "expected `kind` to be a string")?;
         match kind {
             "none" => Ok(StackProbeType::None),
@@ -589,11 +595,11 @@
             StackProbeType::Call => {
                 [(String::from("kind"), "call".to_json())].into_iter().collect()
             }
-            StackProbeType::InlineOrCall { min_llvm_version_for_inline } => [
+            StackProbeType::InlineOrCall { min_llvm_version_for_inline: (maj, min, patch) } => [
                 (String::from("kind"), "inline-or-call".to_json()),
                 (
                     String::from("min-llvm-version-for-inline"),
-                    min_llvm_version_for_inline.to_json(),
+                    Json::Array(vec![maj.to_json(), min.to_json(), patch.to_json()]),
                 ),
             ]
             .into_iter()
@@ -924,6 +930,11 @@
     ("aarch64-apple-tvos", aarch64_apple_tvos),
     ("x86_64-apple-tvos", x86_64_apple_tvos),
 
+    ("armv7k-apple-watchos", armv7k_apple_watchos),
+    ("arm64_32-apple-watchos", arm64_32_apple_watchos),
+    ("x86_64-apple-watchos-sim", x86_64_apple_watchos_sim),
+    ("aarch64-apple-watchos-sim", aarch64_apple_watchos_sim),
+
     ("armebv7r-none-eabi", armebv7r_none_eabi),
     ("armebv7r-none-eabihf", armebv7r_none_eabihf),
     ("armv7r-none-eabi", armv7r_none_eabi),
@@ -980,6 +991,7 @@
     ("riscv32imc-unknown-none-elf", riscv32imc_unknown_none_elf),
     ("riscv32imc-esp-espidf", riscv32imc_esp_espidf),
     ("riscv32imac-unknown-none-elf", riscv32imac_unknown_none_elf),
+    ("riscv32imac-unknown-xous-elf", riscv32imac_unknown_xous_elf),
     ("riscv32gc-unknown-linux-gnu", riscv32gc_unknown_linux_gnu),
     ("riscv32gc-unknown-linux-musl", riscv32gc_unknown_linux_musl),
     ("riscv64imac-unknown-none-elf", riscv64imac_unknown_none_elf),
@@ -1261,12 +1273,6 @@
     ///   - uses SEH-based unwinding,
     ///   - supports control flow guard mechanism.
     pub is_like_msvc: bool,
-    /// Whether the target toolchain is like Emscripten's. Only useful for compiling with
-    /// Emscripten toolchain.
-    /// Defaults to false.
-    pub is_like_emscripten: bool,
-    /// Whether the target toolchain is like Fuchsia's.
-    pub is_like_fuchsia: bool,
     /// Whether a target toolchain is like WASM.
     pub is_like_wasm: bool,
     /// Version of DWARF to use if not using the default.
@@ -1493,9 +1499,7 @@
             is_like_osx: false,
             is_like_solaris: false,
             is_like_windows: false,
-            is_like_emscripten: false,
             is_like_msvc: false,
-            is_like_fuchsia: false,
             is_like_wasm: false,
             dwarf_version: None,
             linker_is_gnu: true,
@@ -1615,7 +1619,8 @@
             | PlatformIntrinsic
             | Unadjusted
             | Cdecl { .. }
-            | EfiApi => true,
+            | EfiApi
+            | RustCold => true,
             X86Interrupt => ["x86", "x86_64"].contains(&&self.arch[..]),
             Aapcs { .. } => "arm" == self.arch,
             CCmseNonSecureCall => ["arm", "aarch64"].contains(&&self.arch[..]),
@@ -1679,7 +1684,7 @@
     }
 
     /// Loads a target descriptor from a JSON object.
-    pub fn from_json(mut obj: Json) -> Result<(Target, TargetWarnings), String> {
+    pub fn from_json(obj: Json) -> Result<(Target, TargetWarnings), String> {
         // While ugly, this code must remain this way to retain
         // compatibility with existing JSON fields and the internal
         // expected naming of the Target and TargetOptions structs.
@@ -1687,9 +1692,14 @@
         // are round-tripped through this code to catch cases where
         // the JSON parser is not updated to match the structs.
 
+        let mut obj = match obj {
+            Value::Object(obj) => obj,
+            _ => return Err("Expected JSON object for target")?,
+        };
+
         let mut get_req_field = |name: &str| {
-            obj.remove_key(name)
-                .and_then(|j| Json::as_string(&j).map(str::to_string))
+            obj.remove(name)
+                .and_then(|j| j.as_str().map(str::to_string))
                 .ok_or_else(|| format!("Field {} in target specification is required", name))
         };
 
@@ -1708,31 +1718,31 @@
         macro_rules! key {
             ($key_name:ident) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
-                if let Some(s) = obj.remove_key(&name).and_then(|j| Json::as_string(&j).map(str::to_string).map(Cow::from)) {
+                if let Some(s) = obj.remove(&name).and_then(|s| s.as_str().map(str::to_string).map(Cow::from)) {
                     base.$key_name = s;
                 }
             } );
             ($key_name:ident = $json_name:expr) => ( {
                 let name = $json_name;
-                if let Some(s) = obj.remove_key(&name).and_then(|j| Json::as_string(&j).map(str::to_string).map(Cow::from)) {
+                if let Some(s) = obj.remove(name).and_then(|s| s.as_str().map(str::to_string).map(Cow::from)) {
                     base.$key_name = s;
                 }
             } );
             ($key_name:ident, bool) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
-                if let Some(s) = obj.remove_key(&name).and_then(|j| Json::as_boolean(&j)) {
+                if let Some(s) = obj.remove(&name).and_then(|b| b.as_bool()) {
                     base.$key_name = s;
                 }
             } );
             ($key_name:ident, u64) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
-                if let Some(s) = obj.remove_key(&name).and_then(|j| Json::as_u64(&j)) {
+                if let Some(s) = obj.remove(&name).and_then(|j| Json::as_u64(&j)) {
                     base.$key_name = s;
                 }
             } );
             ($key_name:ident, Option<u32>) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
-                if let Some(s) = obj.remove_key(&name).and_then(|j| Json::as_u64(&j)) {
+                if let Some(s) = obj.remove(&name).and_then(|b| b.as_u64()) {
                     if s < 1 || s > 5 {
                         return Err("Not a valid DWARF version number".into());
                     }
@@ -1741,13 +1751,13 @@
             } );
             ($key_name:ident, Option<u64>) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
-                if let Some(s) = obj.remove_key(&name).and_then(|j| Json::as_u64(&j)) {
+                if let Some(s) = obj.remove(&name).and_then(|b| b.as_u64()) {
                     base.$key_name = Some(s);
                 }
             } );
             ($key_name:ident, MergeFunctions) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
-                obj.remove_key(&name[..]).and_then(|o| o.as_string().and_then(|s| {
+                obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
                     match s.parse::<MergeFunctions>() {
                         Ok(mergefunc) => base.$key_name = mergefunc,
                         _ => return Some(Err(format!("'{}' is not a valid value for \
@@ -1760,7 +1770,7 @@
             } );
             ($key_name:ident, RelocModel) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
-                obj.remove_key(&name[..]).and_then(|o| o.as_string().and_then(|s| {
+                obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
                     match s.parse::<RelocModel>() {
                         Ok(relocation_model) => base.$key_name = relocation_model,
                         _ => return Some(Err(format!("'{}' is not a valid relocation model. \
@@ -1772,7 +1782,7 @@
             } );
             ($key_name:ident, CodeModel) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
-                obj.remove_key(&name[..]).and_then(|o| o.as_string().and_then(|s| {
+                obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
                     match s.parse::<CodeModel>() {
                         Ok(code_model) => base.$key_name = Some(code_model),
                         _ => return Some(Err(format!("'{}' is not a valid code model. \
@@ -1784,7 +1794,7 @@
             } );
             ($key_name:ident, TlsModel) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
-                obj.remove_key(&name[..]).and_then(|o| o.as_string().and_then(|s| {
+                obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
                     match s.parse::<TlsModel>() {
                         Ok(tls_model) => base.$key_name = tls_model,
                         _ => return Some(Err(format!("'{}' is not a valid TLS model. \
@@ -1796,7 +1806,7 @@
             } );
             ($key_name:ident, PanicStrategy) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
-                obj.remove_key(&name[..]).and_then(|o| o.as_string().and_then(|s| {
+                obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
                     match s {
                         "unwind" => base.$key_name = PanicStrategy::Unwind,
                         "abort" => base.$key_name = PanicStrategy::Abort,
@@ -1809,7 +1819,7 @@
             } );
             ($key_name:ident, RelroLevel) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
-                obj.remove_key(&name[..]).and_then(|o| o.as_string().and_then(|s| {
+                obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
                     match s.parse::<RelroLevel>() {
                         Ok(level) => base.$key_name = level,
                         _ => return Some(Err(format!("'{}' is not a valid value for \
@@ -1821,7 +1831,7 @@
             } );
             ($key_name:ident, SplitDebuginfo) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
-                obj.remove_key(&name[..]).and_then(|o| o.as_string().and_then(|s| {
+                obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
                     match s.parse::<SplitDebuginfo>() {
                         Ok(level) => base.$key_name = level,
                         _ => return Some(Err(format!("'{}' is not a valid value for \
@@ -1833,10 +1843,10 @@
             } );
             ($key_name:ident, list) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
-                if let Some(j) = obj.remove_key(&name){
-                    if let Some(v) = Json::as_array(&j) {
+                if let Some(j) = obj.remove(&name) {
+                    if let Some(v) = j.as_array() {
                         base.$key_name = v.iter()
-                            .map(|a| a.as_string().unwrap().to_string().into())
+                            .map(|a| a.as_str().unwrap().to_string().into())
                             .collect();
                     } else {
                         incorrect_type.push(name)
@@ -1845,10 +1855,10 @@
             } );
             ($key_name:ident, opt_list) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
-                if let Some(j) = obj.remove_key(&name) {
-                    if let Some(v) = Json::as_array(&j) {
+                if let Some(j) = obj.remove(&name) {
+                    if let Some(v) = j.as_array() {
                         base.$key_name = Some(v.iter()
-                            .map(|a| a.as_string().unwrap().to_string().into())
+                            .map(|a| a.as_str().unwrap().to_string().into())
                             .collect());
                     } else {
                         incorrect_type.push(name)
@@ -1857,15 +1867,15 @@
             } );
             ($key_name:ident, optional) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
-                if let Some(o) = obj.remove_key(&name[..]) {
+                if let Some(o) = obj.remove(&name) {
                     base.$key_name = o
-                        .as_string()
+                        .as_str()
                         .map(|s| s.to_string().into());
                 }
             } );
             ($key_name:ident, LldFlavor) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
-                obj.remove_key(&name[..]).and_then(|o| o.as_string().and_then(|s| {
+                obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
                     if let Some(flavor) = LldFlavor::from_str(&s) {
                         base.$key_name = flavor;
                     } else {
@@ -1879,7 +1889,7 @@
             } );
             ($key_name:ident, LinkerFlavor) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
-                obj.remove_key(&name[..]).and_then(|o| o.as_string().and_then(|s| {
+                obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
                     match LinkerFlavor::from_str(s) {
                         Some(linker_flavor) => base.$key_name = linker_flavor,
                         _ => return Some(Err(format!("'{}' is not a valid value for linker-flavor. \
@@ -1890,7 +1900,7 @@
             } );
             ($key_name:ident, StackProbeType) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
-                obj.remove_key(&name[..]).and_then(|o| match StackProbeType::from_json(&o) {
+                obj.remove(&name).and_then(|o| match StackProbeType::from_json(&o) {
                     Ok(v) => {
                         base.$key_name = v;
                         Some(Ok(()))
@@ -1902,10 +1912,10 @@
             } );
             ($key_name:ident, SanitizerSet) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
-                if let Some(o) = obj.remove_key(&name[..]) {
+                if let Some(o) = obj.remove(&name) {
                     if let Some(a) = o.as_array() {
                         for s in a {
-                            base.$key_name |= match s.as_string() {
+                            base.$key_name |= match s.as_str() {
                                 Some("address") => SanitizerSet::ADDRESS,
                                 Some("cfi") => SanitizerSet::CFI,
                                 Some("leak") => SanitizerSet::LEAK,
@@ -1926,7 +1936,7 @@
 
             ($key_name:ident, crt_objects_fallback) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
-                obj.remove_key(&name[..]).and_then(|o| o.as_string().and_then(|s| {
+                obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
                     match s.parse::<CrtObjectsFallback>() {
                         Ok(fallback) => base.$key_name = Some(fallback),
                         _ => return Some(Err(format!("'{}' is not a valid CRT objects fallback. \
@@ -1937,7 +1947,7 @@
             } );
             ($key_name:ident, link_objects) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
-                if let Some(val) = obj.remove_key(&name[..]) {
+                if let Some(val) = obj.remove(&name) {
                     let obj = val.as_object().ok_or_else(|| format!("{}: expected a \
                         JSON object with fields per CRT object kind.", name))?;
                     let mut args = CrtObjects::new();
@@ -1952,7 +1962,7 @@
                             format!("{}.{}: expected a JSON array", name, k)
                         )?.iter().enumerate()
                             .map(|(i,s)| {
-                                let s = s.as_string().ok_or_else(||
+                                let s = s.as_str().ok_or_else(||
                                     format!("{}.{}[{}]: expected a JSON string", name, k, i))?;
                                 Ok(s.to_string().into())
                             })
@@ -1965,7 +1975,7 @@
             } );
             ($key_name:ident, link_args) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
-                if let Some(val) = obj.remove_key(&name[..]) {
+                if let Some(val) = obj.remove(&name) {
                     let obj = val.as_object().ok_or_else(|| format!("{}: expected a \
                         JSON object with fields per linker-flavor.", name))?;
                     let mut args = LinkArgs::new();
@@ -1979,7 +1989,7 @@
                             format!("{}.{}: expected a JSON array", name, k)
                         )?.iter().enumerate()
                             .map(|(i,s)| {
-                                let s = s.as_string().ok_or_else(||
+                                let s = s.as_str().ok_or_else(||
                                     format!("{}.{}[{}]: expected a JSON string", name, k, i))?;
                                 Ok(s.to_string().into())
                             })
@@ -1992,10 +2002,10 @@
             } );
             ($key_name:ident, env) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
-                if let Some(o) = obj.remove_key(&name[..]) {
+                if let Some(o) = obj.remove(&name) {
                     if let Some(a) = o.as_array() {
                         for o in a {
-                            if let Some(s) = o.as_string() {
+                            if let Some(s) = o.as_str() {
                                 let p = s.split('=').collect::<Vec<_>>();
                                 if p.len() == 2 {
                                     let k = p[0].to_string();
@@ -2011,7 +2021,7 @@
             } );
             ($key_name:ident, Option<Abi>) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
-                obj.remove_key(&name[..]).and_then(|o| o.as_string().and_then(|s| {
+                obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
                     match lookup_abi(s) {
                         Some(abi) => base.$key_name = Some(abi),
                         _ => return Some(Err(format!("'{}' is not a valid value for abi", s))),
@@ -2020,28 +2030,28 @@
                 })).unwrap_or(Ok(()))
             } );
             ($key_name:ident, TargetFamilies) => ( {
-                if let Some(value) = obj.remove_key("target-family") {
-                    if let Some(v) = Json::as_array(&value) {
+                if let Some(value) = obj.remove("target-family") {
+                    if let Some(v) = value.as_array() {
                         base.$key_name = v.iter()
-                            .map(|a| a.as_string().unwrap().to_string().into())
+                            .map(|a| a.as_str().unwrap().to_string().into())
                             .collect();
-                    } else if let Some(v) = Json::as_string(&value) {
+                    } else if let Some(v) = value.as_str() {
                         base.$key_name = vec![v.to_string().into()].into();
                     }
                 }
             } );
         }
 
-        if let Some(j) = obj.remove_key("target-endian") {
-            if let Some(s) = Json::as_string(&j) {
+        if let Some(j) = obj.remove("target-endian") {
+            if let Some(s) = j.as_str() {
                 base.endian = s.parse()?;
             } else {
                 incorrect_type.push("target-endian".into())
             }
         }
 
-        if let Some(fp) = obj.remove_key("frame-pointer") {
-            if let Some(s) = Json::as_string(&fp) {
+        if let Some(fp) = obj.remove("frame-pointer") {
+            if let Some(s) = fp.as_str() {
                 base.frame_pointer = s
                     .parse()
                     .map_err(|()| format!("'{}' is not a valid value for frame-pointer", s))?;
@@ -2094,8 +2104,6 @@
         key!(is_like_solaris, bool);
         key!(is_like_windows, bool);
         key!(is_like_msvc, bool);
-        key!(is_like_emscripten, bool);
-        key!(is_like_fuchsia, bool);
         key!(is_like_wasm, bool);
         key!(dwarf_version, Option<u32>);
         key!(linker_is_gnu, bool);
@@ -2153,8 +2161,8 @@
             // This can cause unfortunate ICEs later down the line.
             return Err("may not set is_builtin for targets not built-in".into());
         }
-        // Each field should have been read using `Json::remove_key` so any keys remaining are unused.
-        let remaining_keys = obj.as_object().ok_or("Expected JSON object for target")?.keys();
+        // Each field should have been read using `Json::remove` so any keys remaining are unused.
+        let remaining_keys = obj.keys();
         Ok((
             base,
             TargetWarnings { unused_fields: remaining_keys.cloned().collect(), incorrect_type },
@@ -2167,7 +2175,7 @@
             TargetTriple::TargetTriple(ref target_triple) => {
                 load_builtin(target_triple).expect("built-in target")
             }
-            TargetTriple::TargetPath(..) => {
+            TargetTriple::TargetJson { .. } => {
                 panic!("built-in targets doens't support target-paths")
             }
         }
@@ -2186,13 +2194,12 @@
         target_triple: &TargetTriple,
         sysroot: &Path,
     ) -> Result<(Target, TargetWarnings), String> {
-        use rustc_serialize::json;
         use std::env;
         use std::fs;
 
         fn load_file(path: &Path) -> Result<(Target, TargetWarnings), String> {
             let contents = fs::read_to_string(path).map_err(|e| e.to_string())?;
-            let obj = json::from_str(&contents).map_err(|e| e.to_string())?;
+            let obj = serde_json::from_str(&contents).map_err(|e| e.to_string())?;
             Target::from_json(obj)
         }
 
@@ -2233,11 +2240,9 @@
 
                 Err(format!("Could not find specification for target {:?}", target_triple))
             }
-            TargetTriple::TargetPath(ref target_path) => {
-                if target_path.is_file() {
-                    return load_file(&target_path);
-                }
-                Err(format!("Target path {:?} is not a valid file", target_path))
+            TargetTriple::TargetJson { ref contents, .. } => {
+                let obj = serde_json::from_str(contents).map_err(|e| e.to_string())?;
+                Target::from_json(obj)
             }
         }
     }
@@ -2245,7 +2250,7 @@
 
 impl ToJson for Target {
     fn to_json(&self) -> Json {
-        let mut d = BTreeMap::new();
+        let mut d = serde_json::Map::new();
         let default: TargetOptions = Default::default();
 
         macro_rules! target_val {
@@ -2343,8 +2348,6 @@
         target_option_val!(is_like_solaris);
         target_option_val!(is_like_windows);
         target_option_val!(is_like_msvc);
-        target_option_val!(is_like_emscripten);
-        target_option_val!(is_like_fuchsia);
         target_option_val!(is_like_wasm);
         target_option_val!(dwarf_version);
         target_option_val!(linker_is_gnu);
@@ -2406,10 +2409,77 @@
 }
 
 /// Either a target triple string or a path to a JSON file.
-#[derive(PartialEq, Clone, Debug, Hash, Encodable, Decodable)]
+#[derive(Clone, Debug)]
 pub enum TargetTriple {
     TargetTriple(String),
-    TargetPath(PathBuf),
+    TargetJson {
+        /// Warning: This field may only be used by rustdoc. Using it anywhere else will lead to
+        /// inconsistencies as it is discarded during serialization.
+        path_for_rustdoc: PathBuf,
+        triple: String,
+        contents: String,
+    },
+}
+
+// Use a manual implementation to ignore the path field
+impl PartialEq for TargetTriple {
+    fn eq(&self, other: &Self) -> bool {
+        match (self, other) {
+            (Self::TargetTriple(l0), Self::TargetTriple(r0)) => l0 == r0,
+            (
+                Self::TargetJson { path_for_rustdoc: _, triple: l_triple, contents: l_contents },
+                Self::TargetJson { path_for_rustdoc: _, triple: r_triple, contents: r_contents },
+            ) => l_triple == r_triple && l_contents == r_contents,
+            _ => false,
+        }
+    }
+}
+
+// Use a manual implementation to ignore the path field
+impl Hash for TargetTriple {
+    fn hash<H: Hasher>(&self, state: &mut H) -> () {
+        match self {
+            TargetTriple::TargetTriple(triple) => {
+                0u8.hash(state);
+                triple.hash(state)
+            }
+            TargetTriple::TargetJson { path_for_rustdoc: _, triple, contents } => {
+                1u8.hash(state);
+                triple.hash(state);
+                contents.hash(state)
+            }
+        }
+    }
+}
+
+// Use a manual implementation to prevent encoding the target json file path in the crate metadata
+impl<S: Encoder> Encodable<S> for TargetTriple {
+    fn encode(&self, s: &mut S) {
+        match self {
+            TargetTriple::TargetTriple(triple) => s.emit_enum_variant(0, |s| s.emit_str(triple)),
+            TargetTriple::TargetJson { path_for_rustdoc: _, triple, contents } => s
+                .emit_enum_variant(1, |s| {
+                    s.emit_str(triple);
+                    s.emit_str(contents)
+                }),
+        }
+    }
+}
+
+impl<D: Decoder> Decodable<D> for TargetTriple {
+    fn decode(d: &mut D) -> Self {
+        match d.read_usize() {
+            0 => TargetTriple::TargetTriple(d.read_str().to_owned()),
+            1 => TargetTriple::TargetJson {
+                path_for_rustdoc: PathBuf::new(),
+                triple: d.read_str().to_owned(),
+                contents: d.read_str().to_owned(),
+            },
+            _ => {
+                panic!("invalid enum variant tag while decoding `TargetTriple`, expected 0..2");
+            }
+        }
+    }
 }
 
 impl TargetTriple {
@@ -2421,7 +2491,19 @@
     /// Creates a target triple from the passed target path.
     pub fn from_path(path: &Path) -> Result<Self, io::Error> {
         let canonicalized_path = path.canonicalize()?;
-        Ok(TargetTriple::TargetPath(canonicalized_path))
+        let contents = std::fs::read_to_string(&canonicalized_path).map_err(|err| {
+            io::Error::new(
+                io::ErrorKind::InvalidInput,
+                format!("target path {:?} is not a valid file: {}", canonicalized_path, err),
+            )
+        })?;
+        let triple = canonicalized_path
+            .file_stem()
+            .expect("target path must not be empty")
+            .to_str()
+            .expect("target path must be valid unicode")
+            .to_owned();
+        Ok(TargetTriple::TargetJson { path_for_rustdoc: canonicalized_path, triple, contents })
     }
 
     /// Returns a string triple for this target.
@@ -2429,12 +2511,8 @@
     /// If this target is a path, the file name (without extension) is returned.
     pub fn triple(&self) -> &str {
         match *self {
-            TargetTriple::TargetTriple(ref triple) => triple,
-            TargetTriple::TargetPath(ref path) => path
-                .file_stem()
-                .expect("target path must not be empty")
-                .to_str()
-                .expect("target path must be valid unicode"),
+            TargetTriple::TargetTriple(ref triple)
+            | TargetTriple::TargetJson { ref triple, .. } => triple,
         }
     }
 
@@ -2444,16 +2522,15 @@
     /// by `triple()`.
     pub fn debug_triple(&self) -> String {
         use std::collections::hash_map::DefaultHasher;
-        use std::hash::{Hash, Hasher};
 
-        let triple = self.triple();
-        if let TargetTriple::TargetPath(ref path) = *self {
-            let mut hasher = DefaultHasher::new();
-            path.hash(&mut hasher);
-            let hash = hasher.finish();
-            format!("{}-{}", triple, hash)
-        } else {
-            triple.into()
+        match self {
+            TargetTriple::TargetTriple(triple) => triple.to_owned(),
+            TargetTriple::TargetJson { path_for_rustdoc: _, triple, contents: content } => {
+                let mut hasher = DefaultHasher::new();
+                content.hash(&mut hasher);
+                let hash = hasher.finish();
+                format!("{}-{}", triple, hash)
+            }
         }
     }
 }
diff --git a/compiler/rustc_target/src/spec/riscv32imac_unknown_xous_elf.rs b/compiler/rustc_target/src/spec/riscv32imac_unknown_xous_elf.rs
new file mode 100644
index 0000000..b46ca15
--- /dev/null
+++ b/compiler/rustc_target/src/spec/riscv32imac_unknown_xous_elf.rs
@@ -0,0 +1,24 @@
+use crate::spec::{LinkerFlavor, LldFlavor, PanicStrategy, RelocModel};
+use crate::spec::{Target, TargetOptions};
+
+pub fn target() -> Target {
+    Target {
+        data_layout: "e-m:e-p:32:32-i64:64-n32-S128".into(),
+        llvm_target: "riscv32".into(),
+        pointer_width: 32,
+        arch: "riscv32".into(),
+
+        options: TargetOptions {
+            os: "xous".into(),
+            linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
+            linker: Some("rust-lld".into()),
+            cpu: "generic-rv32".into(),
+            max_atomic_width: Some(32),
+            features: "+m,+a,+c".into(),
+            executables: true,
+            panic_strategy: PanicStrategy::Abort,
+            relocation_model: RelocModel::Static,
+            ..Default::default()
+        },
+    }
+}
diff --git a/compiler/rustc_target/src/spec/tests/tests_impl.rs b/compiler/rustc_target/src/spec/tests/tests_impl.rs
index 6730319..0865ca7 100644
--- a/compiler/rustc_target/src/spec/tests/tests_impl.rs
+++ b/compiler/rustc_target/src/spec/tests/tests_impl.rs
@@ -8,7 +8,12 @@
 
 impl Target {
     fn check_consistency(&self) {
+        assert_eq!(self.is_like_osx, self.vendor == "apple");
+        assert_eq!(self.is_like_solaris, self.os == "solaris" || self.os == "illumos");
+        assert_eq!(self.is_like_windows, self.os == "windows" || self.os == "uefi");
+        assert_eq!(self.is_like_wasm, self.arch == "wasm32" || self.arch == "wasm64");
         assert!(self.is_like_windows || !self.is_like_msvc);
+
         // Check that LLD with the given flavor is treated identically to the linker it emulates.
         // If your target really needs to deviate from the rules below, except it and document the
         // reasons.
diff --git a/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs b/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs
index b34cac4..f1087db 100644
--- a/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs
+++ b/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs
@@ -16,15 +16,7 @@
     let mut post_link_args = LinkArgs::new();
     post_link_args.insert(
         LinkerFlavor::Em,
-        vec![
-            "-s".into(),
-            "ERROR_ON_UNDEFINED_SYMBOLS=1".into(),
-            "-s".into(),
-            "ASSERTIONS=1".into(),
-            "-s".into(),
-            "ABORTING_MALLOC=0".into(),
-            "-Wl,--fatal-warnings".into(),
-        ],
+        vec!["-sABORTING_MALLOC=0".into(), "-Wl,--fatal-warnings".into()],
     );
 
     let opts = TargetOptions {
@@ -34,8 +26,8 @@
         // functionality, and a .wasm file.
         exe_suffix: ".js".into(),
         linker: None,
-        is_like_emscripten: true,
         panic_strategy: PanicStrategy::Unwind,
+        no_default_libraries: false,
         post_link_args,
         families: cvs!["unix", "wasm"],
         ..options
diff --git a/compiler/rustc_target/src/spec/x86_64_apple_watchos_sim.rs b/compiler/rustc_target/src/spec/x86_64_apple_watchos_sim.rs
new file mode 100644
index 0000000..4dff3c2
--- /dev/null
+++ b/compiler/rustc_target/src/spec/x86_64_apple_watchos_sim.rs
@@ -0,0 +1,35 @@
+use super::apple_sdk_base::{opts, Arch};
+use crate::spec::{StackProbeType, Target, TargetOptions};
+
+pub fn target() -> Target {
+    let base = opts("watchos", Arch::X86_64);
+
+    let arch = "x86_64";
+    let llvm_target = super::apple_base::watchos_sim_llvm_target(arch);
+
+    Target {
+        llvm_target: llvm_target.into(),
+        pointer_width: 64,
+        data_layout: "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+            .into(),
+        arch: "x86_64".into(),
+        options: TargetOptions {
+            max_atomic_width: Some(64),
+            // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
+            stack_probes: StackProbeType::Call,
+            forces_embed_bitcode: true,
+            // Taken from a clang build on Xcode 11.4.1.
+            // These arguments are not actually invoked - they just have
+            // to look right to pass App Store validation.
+            bitcode_llvm_cmdline: "-triple\0\
+                x86_64-apple-watchos5.0-simulator\0\
+                -emit-obj\0\
+                -disable-llvm-passes\0\
+                -target-abi\0\
+                darwinpcs\0\
+                -Os\0"
+                .into(),
+            ..base
+        },
+    }
+}
diff --git a/compiler/rustc_target/src/tests.rs b/compiler/rustc_target/src/tests.rs
index 3a737b3..7637517 100644
--- a/compiler/rustc_target/src/tests.rs
+++ b/compiler/rustc_target/src/tests.rs
@@ -1,10 +1,8 @@
 use crate::spec::Target;
-use rustc_serialize::json::Json;
-use std::str::FromStr;
 
 #[test]
 fn report_unused_fields() {
-    let json = Json::from_str(
+    let json = serde_json::from_str(
         r#"
     {
         "arch": "powerpc64",
@@ -23,7 +21,7 @@
 
 #[test]
 fn report_incorrect_json_type() {
-    let json = Json::from_str(
+    let json = serde_json::from_str(
         r#"
     {
         "arch": "powerpc64",
@@ -42,7 +40,7 @@
 
 #[test]
 fn no_warnings_for_valid_target() {
-    let json = Json::from_str(
+    let json = serde_json::from_str(
         r#"
     {
         "arch": "powerpc64",
diff --git a/compiler/rustc_trait_selection/src/lib.rs b/compiler/rustc_trait_selection/src/lib.rs
index 0dd4974..44ff3fd 100644
--- a/compiler/rustc_trait_selection/src/lib.rs
+++ b/compiler/rustc_trait_selection/src/lib.rs
@@ -1,4 +1,4 @@
-//! This crates defines the trait resolution method.
+//! This crate defines the trait resolution method.
 //!
 //! - **Traits.** Trait resolution is implemented in the `traits` module.
 //!
@@ -14,13 +14,12 @@
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![feature(box_patterns)]
 #![feature(control_flow_enum)]
-#![feature(crate_visibility_modifier)]
-#![cfg_attr(bootstrap, feature(derive_default_enum))]
 #![feature(drain_filter)]
 #![feature(hash_drain_filter)]
 #![feature(label_break_value)]
 #![feature(let_chains)]
 #![feature(let_else)]
+#![feature(if_let_guard)]
 #![feature(never_type)]
 #![recursion_limit = "512"] // For rustdoc
 
diff --git a/compiler/rustc_trait_selection/src/opaque_types.rs b/compiler/rustc_trait_selection/src/opaque_types.rs
index 238c6d9..9dd8588 100644
--- a/compiler/rustc_trait_selection/src/opaque_types.rs
+++ b/compiler/rustc_trait_selection/src/opaque_types.rs
@@ -7,7 +7,7 @@
 use rustc_infer::infer::error_reporting::unexpected_hidden_region_diagnostic;
 use rustc_infer::infer::{InferCtxt, TyCtxtInferExt as _};
 use rustc_infer::traits::{Obligation, ObligationCause, TraitEngine};
-use rustc_middle::ty::fold::{TypeFoldable, TypeFolder};
+use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
 use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts};
 use rustc_middle::ty::{self, OpaqueHiddenType, OpaqueTypeKey, ToPredicate, Ty, TyCtxt};
 use rustc_span::Span;
@@ -209,7 +209,7 @@
             GenericArgKind::Lifetime(lt) => {
                 matches!(*lt, ty::ReEarlyBound(_) | ty::ReFree(_))
             }
-            GenericArgKind::Const(ct) => matches!(ct.val(), ty::ConstKind::Param(_)),
+            GenericArgKind::Const(ct) => matches!(ct.kind(), ty::ConstKind::Param(_)),
         };
 
         if arg_is_param {
@@ -452,7 +452,7 @@
     fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
         trace!("checking const {:?}", ct);
         // Find a const parameter
-        match ct.val() {
+        match ct.kind() {
             ty::ConstKind::Param(..) => {
                 // Look it up in the substitution list.
                 match self.map.get(&ct.into()).map(|k| k.unpack()) {
@@ -500,7 +500,7 @@
 /// Requires that trait definitions have been processed so that we can
 /// elaborate predicates and walk supertraits.
 #[instrument(skip(tcx, predicates), level = "debug")]
-crate fn required_region_bounds<'tcx>(
+pub(crate) fn required_region_bounds<'tcx>(
     tcx: TyCtxt<'tcx>,
     erased_self_ty: Ty<'tcx>,
     predicates: impl Iterator<Item = ty::Predicate<'tcx>>,
diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
index 79e9635..a63790b 100644
--- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs
+++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
@@ -6,7 +6,8 @@
 use crate::infer::region_constraints::{Constraint, RegionConstraintData};
 use crate::infer::InferCtxt;
 use crate::traits::project::ProjectAndUnifyResult;
-use rustc_middle::ty::fold::TypeFolder;
+use rustc_middle::mir::interpret::ErrorHandled;
+use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable};
 use rustc_middle::ty::{Region, RegionVid, Term};
 
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
@@ -828,13 +829,22 @@
                 }
                 ty::PredicateKind::ConstEquate(c1, c2) => {
                     let evaluate = |c: ty::Const<'tcx>| {
-                        if let ty::ConstKind::Unevaluated(unevaluated) = c.val() {
+                        if let ty::ConstKind::Unevaluated(unevaluated) = c.kind() {
                             match select.infcx().const_eval_resolve(
                                 obligation.param_env,
                                 unevaluated,
                                 Some(obligation.cause.span),
                             ) {
-                                Ok(val) => Ok(ty::Const::from_value(select.tcx(), val, c.ty())),
+                                Ok(Some(valtree)) => {
+                                    Ok(ty::Const::from_value(select.tcx(), valtree, c.ty()))
+                                }
+                                Ok(None) => {
+                                    let tcx = self.tcx;
+                                    let def_id = unevaluated.def.did;
+                                    let reported = tcx.sess.struct_span_err(tcx.def_span(def_id), &format!("unable to construct a constant value for the unevaluated constant {:?}", unevaluated)).emit();
+
+                                    Err(ErrorHandled::Reported(reported))
+                                }
                                 Err(err) => Err(err),
                             }
                         } else {
diff --git a/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs b/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs
index 93c2f20..592b0ab4 100644
--- a/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs
@@ -17,7 +17,7 @@
 }
 
 impl FulfillmentContext<'_> {
-    crate fn new() -> Self {
+    pub(crate) fn new() -> Self {
         FulfillmentContext {
             obligations: FxIndexSet::default(),
             relationships: FxHashMap::default(),
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
index d09cc4f..b37db4b 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -5,7 +5,7 @@
 //! [trait-specialization]: https://rustc-dev-guide.rust-lang.org/traits/specialization.html
 
 use crate::infer::outlives::env::OutlivesEnvironment;
-use crate::infer::{CombinedSnapshot, InferOk, RegionckMode};
+use crate::infer::{CombinedSnapshot, InferOk};
 use crate::traits::select::IntercrateAmbiguityCause;
 use crate::traits::util::impl_subject_and_oblig;
 use crate::traits::SkipLeakCheck;
@@ -20,7 +20,7 @@
 use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
 use rustc_infer::traits::{util, TraitEngine};
 use rustc_middle::traits::specialization_graph::OverlapMode;
-use rustc_middle::ty::fast_reject::{self, TreatParams};
+use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::subst::Subst;
 use rustc_middle::ty::{self, ImplSubject, Ty, TyCtxt};
@@ -79,26 +79,21 @@
     // Before doing expensive operations like entering an inference context, do
     // a quick check via fast_reject to tell if the impl headers could possibly
     // unify.
+    let drcx = DeepRejectCtxt { treat_obligation_params: TreatParams::AsInfer };
     let impl1_ref = tcx.impl_trait_ref(impl1_def_id);
     let impl2_ref = tcx.impl_trait_ref(impl2_def_id);
-
-    // Check if any of the input types definitely do not unify.
-    if iter::zip(
-        impl1_ref.iter().flat_map(|tref| tref.substs.types()),
-        impl2_ref.iter().flat_map(|tref| tref.substs.types()),
-    )
-    .any(|(ty1, ty2)| {
-        let t1 = fast_reject::simplify_type(tcx, ty1, TreatParams::AsPlaceholders);
-        let t2 = fast_reject::simplify_type(tcx, ty2, TreatParams::AsPlaceholders);
-
-        if let (Some(t1), Some(t2)) = (t1, t2) {
-            // Simplified successfully
-            t1 != t2
-        } else {
-            // Types might unify
-            false
+    let may_overlap = match (impl1_ref, impl2_ref) {
+        (Some(a), Some(b)) => iter::zip(a.substs, b.substs)
+            .all(|(arg1, arg2)| drcx.generic_args_may_unify(arg1, arg2)),
+        (None, None) => {
+            let self_ty1 = tcx.type_of(impl1_def_id);
+            let self_ty2 = tcx.type_of(impl2_def_id);
+            drcx.types_may_unify(self_ty1, self_ty2)
         }
-    }) {
+        _ => bug!("unexpected impls: {impl1_def_id:?} {impl2_def_id:?}"),
+    };
+
+    if !may_overlap {
         // Some types involved are definitely different, so the impls couldn't possibly overlap.
         debug!("overlapping_impls: fast_reject early-exit");
         return no_overlap();
@@ -418,7 +413,7 @@
         param_env,
     );
 
-    let errors = infcx.resolve_regions(region_context, &outlives_env, RegionckMode::default());
+    let errors = infcx.resolve_regions(region_context, &outlives_env);
 
     if !errors.is_empty() {
         return false;
@@ -519,7 +514,7 @@
 /// 3. Before this local type, no generic type parameter of the impl must
 ///    be reachable through fundamental types.
 ///     - e.g. `impl<T> Trait<LocalType> for Vec<T>` is fine, as `Vec` is not fundamental.
-///     - while `impl<T> Trait<LocalType for Box<T>` results in an error, as `T` is
+///     - while `impl<T> Trait<LocalType> for Box<T>` results in an error, as `T` is
 ///       reachable through the fundamental type `Box`.
 /// 4. Every type in the local key parameter not known in C, going
 ///    through the parameter's type tree, must appear only as a subtree of
@@ -645,7 +640,7 @@
                 .substs
                 .types()
                 .flat_map(|ty| uncover_fundamental_ty(tcx, ty, in_crate))
-                .find(|ty| ty_is_local_constructor(*ty, in_crate));
+                .find(|&ty| ty_is_local_constructor(tcx, ty, in_crate));
 
             debug!("orphan_check_trait_ref: uncovered ty local_type: `{:?}`", local_type);
 
@@ -677,7 +672,7 @@
     ty: Ty<'tcx>,
     in_crate: InCrate,
 ) -> Vec<Ty<'tcx>> {
-    if ty_is_local_constructor(ty, in_crate) {
+    if ty_is_local_constructor(tcx, ty, in_crate) {
         Vec::new()
     } else {
         match fundamental_ty_inner_tys(tcx, ty) {
@@ -730,7 +725,7 @@
     }
 }
 
-fn ty_is_local_constructor(ty: Ty<'_>, in_crate: InCrate) -> bool {
+fn ty_is_local_constructor(tcx: TyCtxt<'_>, ty: Ty<'_>, in_crate: InCrate) -> bool {
     debug!("ty_is_local_constructor({:?})", ty);
 
     match *ty.kind() {
@@ -789,11 +784,6 @@
             false
         }
 
-        ty::Closure(..) => {
-            // Similar to the `Opaque` case (#83613).
-            false
-        }
-
         ty::Dynamic(ref tt, ..) => {
             if let Some(principal) = tt.principal() {
                 def_id_is_local(principal.def_id(), in_crate)
@@ -804,8 +794,20 @@
 
         ty::Error(_) => true,
 
-        ty::Generator(..) | ty::GeneratorWitness(..) => {
-            bug!("ty_is_local invoked on unexpected type: {:?}", ty)
+        // These variants should never appear during coherence checking because they
+        // cannot be named directly.
+        //
+        // They could be indirectly used through an opaque type. While using opaque types
+        // in impls causes an error, this path can still be hit afterwards.
+        //
+        // See `test/ui/coherence/coherence-with-closure.rs` for an example where this
+        // could happens.
+        ty::Closure(..) | ty::Generator(..) | ty::GeneratorWitness(..) => {
+            tcx.sess.delay_span_bug(
+                DUMMY_SP,
+                format!("ty_is_local invoked on closure or generator: {:?}", ty),
+            );
+            true
         }
     }
 }
diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
index 27ce08e..5d08ea9 100644
--- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
+++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
@@ -13,9 +13,7 @@
 use rustc_index::vec::IndexVec;
 use rustc_infer::infer::InferCtxt;
 use rustc_middle::mir;
-use rustc_middle::mir::interpret::{
-    ConstValue, ErrorHandled, LitToConstError, LitToConstInput, Scalar,
-};
+use rustc_middle::mir::interpret::{ErrorHandled, LitToConstError, LitToConstInput};
 use rustc_middle::thir;
 use rustc_middle::thir::abstract_const::{self, Node, NodeId, NotConstEvaluatable};
 use rustc_middle::ty::subst::{Subst, SubstsRef};
@@ -39,150 +37,148 @@
     let tcx = infcx.tcx;
 
     if tcx.features().generic_const_exprs {
-        match AbstractConst::new(tcx, uv)? {
-            // We are looking at a generic abstract constant.
-            Some(ct) => {
-                if satisfied_from_param_env(tcx, ct, param_env)? {
-                    return Ok(());
-                }
-
-                // We were unable to unify the abstract constant with
-                // a constant found in the caller bounds, there are
-                // now three possible cases here.
-                #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
-                enum FailureKind {
-                    /// The abstract const still references an inference
-                    /// variable, in this case we return `TooGeneric`.
-                    MentionsInfer,
-                    /// The abstract const references a generic parameter,
-                    /// this means that we emit an error here.
-                    MentionsParam,
-                    /// The substs are concrete enough that we can simply
-                    /// try and evaluate the given constant.
-                    Concrete,
-                }
-                let mut failure_kind = FailureKind::Concrete;
-                walk_abstract_const::<!, _>(tcx, ct, |node| match node.root(tcx) {
-                    Node::Leaf(leaf) => {
-                        if leaf.has_infer_types_or_consts() {
-                            failure_kind = FailureKind::MentionsInfer;
-                        } else if leaf.has_param_types_or_consts() {
-                            failure_kind = cmp::min(failure_kind, FailureKind::MentionsParam);
-                        }
-
-                        ControlFlow::CONTINUE
-                    }
-                    Node::Cast(_, _, ty) => {
-                        if ty.has_infer_types_or_consts() {
-                            failure_kind = FailureKind::MentionsInfer;
-                        } else if ty.has_param_types_or_consts() {
-                            failure_kind = cmp::min(failure_kind, FailureKind::MentionsParam);
-                        }
-
-                        ControlFlow::CONTINUE
-                    }
-                    Node::Binop(_, _, _) | Node::UnaryOp(_, _) | Node::FunctionCall(_, _) => {
-                        ControlFlow::CONTINUE
-                    }
-                });
-
-                match failure_kind {
-                    FailureKind::MentionsInfer => {
-                        return Err(NotConstEvaluatable::MentionsInfer);
-                    }
-                    FailureKind::MentionsParam => {
-                        return Err(NotConstEvaluatable::MentionsParam);
-                    }
-                    FailureKind::Concrete => {
-                        // Dealt with below by the same code which handles this
-                        // without the feature gate.
-                    }
-                }
+        if let Some(ct) = AbstractConst::new(tcx, uv)? {
+            if satisfied_from_param_env(tcx, ct, param_env)? {
+                return Ok(());
             }
-            None => {
-                // If we are dealing with a concrete constant, we can
-                // reuse the old code path and try to evaluate
-                // the constant.
+
+            // We were unable to unify the abstract constant with
+            // a constant found in the caller bounds, there are
+            // now three possible cases here.
+            #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
+            enum FailureKind {
+                /// The abstract const still references an inference
+                /// variable, in this case we return `TooGeneric`.
+                MentionsInfer,
+                /// The abstract const references a generic parameter,
+                /// this means that we emit an error here.
+                MentionsParam,
+                /// The substs are concrete enough that we can simply
+                /// try and evaluate the given constant.
+                Concrete,
+            }
+            let mut failure_kind = FailureKind::Concrete;
+            walk_abstract_const::<!, _>(tcx, ct, |node| match node.root(tcx) {
+                Node::Leaf(leaf) => {
+                    if leaf.has_infer_types_or_consts() {
+                        failure_kind = FailureKind::MentionsInfer;
+                    } else if leaf.has_param_types_or_consts() {
+                        failure_kind = cmp::min(failure_kind, FailureKind::MentionsParam);
+                    }
+
+                    ControlFlow::CONTINUE
+                }
+                Node::Cast(_, _, ty) => {
+                    if ty.has_infer_types_or_consts() {
+                        failure_kind = FailureKind::MentionsInfer;
+                    } else if ty.has_param_types_or_consts() {
+                        failure_kind = cmp::min(failure_kind, FailureKind::MentionsParam);
+                    }
+
+                    ControlFlow::CONTINUE
+                }
+                Node::Binop(_, _, _) | Node::UnaryOp(_, _) | Node::FunctionCall(_, _) => {
+                    ControlFlow::CONTINUE
+                }
+            });
+
+            match failure_kind {
+                FailureKind::MentionsInfer => {
+                    return Err(NotConstEvaluatable::MentionsInfer);
+                }
+                FailureKind::MentionsParam => {
+                    return Err(NotConstEvaluatable::MentionsParam);
+                }
+                // returned below
+                FailureKind::Concrete => {}
             }
         }
-    }
-
-    let future_compat_lint = || {
-        if let Some(local_def_id) = uv.def.did.as_local() {
-            infcx.tcx.struct_span_lint_hir(
-                lint::builtin::CONST_EVALUATABLE_UNCHECKED,
-                infcx.tcx.hir().local_def_id_to_hir_id(local_def_id),
-                span,
-                |err| {
-                    err.build("cannot use constants which depend on generic parameters in types")
-                        .emit();
-                },
-            );
-        }
-    };
-
-    // FIXME: We should only try to evaluate a given constant here if it is fully concrete
-    // as we don't want to allow things like `[u8; std::mem::size_of::<*mut T>()]`.
-    //
-    // We previously did not check this, so we only emit a future compat warning if
-    // const evaluation succeeds and the given constant is still polymorphic for now
-    // and hopefully soon change this to an error.
-    //
-    // See #74595 for more details about this.
-    let concrete = infcx.const_eval_resolve(param_env, uv.expand(), Some(span));
-
-    if concrete.is_ok() && uv.substs.has_param_types_or_consts() {
-        match infcx.tcx.def_kind(uv.def.did) {
-            DefKind::AnonConst | DefKind::InlineConst => {
-                let mir_body = infcx.tcx.mir_for_ctfe_opt_const_arg(uv.def);
-
-                if mir_body.is_polymorphic {
-                    future_compat_lint();
-                }
+        let concrete = infcx.const_eval_resolve(param_env, uv.expand(), Some(span));
+        match concrete {
+            Err(ErrorHandled::TooGeneric) => Err(if !uv.has_infer_types_or_consts() {
+                infcx
+                    .tcx
+                    .sess
+                    .delay_span_bug(span, &format!("unexpected `TooGeneric` for {:?}", uv));
+                NotConstEvaluatable::MentionsParam
+            } else {
+                NotConstEvaluatable::MentionsInfer
+            }),
+            Err(ErrorHandled::Linted) => {
+                let reported = infcx
+                    .tcx
+                    .sess
+                    .delay_span_bug(span, "constant in type had error reported as lint");
+                Err(NotConstEvaluatable::Error(reported))
             }
-            _ => future_compat_lint(),
+            Err(ErrorHandled::Reported(e)) => Err(NotConstEvaluatable::Error(e)),
+            Ok(_) => Ok(()),
         }
-    }
+    } else {
+        // FIXME: We should only try to evaluate a given constant here if it is fully concrete
+        // as we don't want to allow things like `[u8; std::mem::size_of::<*mut T>()]`.
+        //
+        // We previously did not check this, so we only emit a future compat warning if
+        // const evaluation succeeds and the given constant is still polymorphic for now
+        // and hopefully soon change this to an error.
+        //
+        // See #74595 for more details about this.
+        let concrete = infcx.const_eval_resolve(param_env, uv.expand(), Some(span));
 
-    // If we're evaluating a foreign constant, under a nightly compiler without generic
-    // const exprs, AND it would've passed if that expression had been evaluated with
-    // generic const exprs, then suggest using generic const exprs.
-    if concrete.is_err()
-        && tcx.sess.is_nightly_build()
-        && !uv.def.did.is_local()
-        && !tcx.features().generic_const_exprs
-        && let Ok(Some(ct)) = AbstractConst::new(tcx, uv)
-        && satisfied_from_param_env(tcx, ct, param_env) == Ok(true)
-    {
-        tcx.sess
-            .struct_span_fatal(
-                // Slightly better span than just using `span` alone
-                if span == rustc_span::DUMMY_SP { tcx.def_span(uv.def.did) } else { span },
-                "failed to evaluate generic const expression",
-            )
-            .note("the crate this constant originates from uses `#![feature(generic_const_exprs)]`")
-            .span_suggestion_verbose(
-                rustc_span::DUMMY_SP,
-                "consider enabling this feature",
-                "#![feature(generic_const_exprs)]\n".to_string(),
-                rustc_errors::Applicability::MaybeIncorrect,
-            )
-            .emit()
-    }
+        match concrete {
+          // If we're evaluating a foreign constant, under a nightly compiler without generic
+          // const exprs, AND it would've passed if that expression had been evaluated with
+          // generic const exprs, then suggest using generic const exprs.
+          Err(_) if tcx.sess.is_nightly_build()
+            && let Ok(Some(ct)) = AbstractConst::new(tcx, uv)
+            && satisfied_from_param_env(tcx, ct, param_env) == Ok(true) => {
+              tcx.sess
+                  .struct_span_fatal(
+                      // Slightly better span than just using `span` alone
+                      if span == rustc_span::DUMMY_SP { tcx.def_span(uv.def.did) } else { span },
+                      "failed to evaluate generic const expression",
+                  )
+                  .note("the crate this constant originates from uses `#![feature(generic_const_exprs)]`")
+                  .span_suggestion_verbose(
+                      rustc_span::DUMMY_SP,
+                      "consider enabling this feature",
+                      "#![feature(generic_const_exprs)]\n",
+                      rustc_errors::Applicability::MaybeIncorrect,
+                  )
+                  .emit()
+            }
 
-    debug!(?concrete, "is_const_evaluatable");
-    match concrete {
-        Err(ErrorHandled::TooGeneric) => Err(match uv.has_infer_types_or_consts() {
-            true => NotConstEvaluatable::MentionsInfer,
-            false => NotConstEvaluatable::MentionsParam,
-        }),
-        Err(ErrorHandled::Linted) => {
-            let reported =
-                infcx.tcx.sess.delay_span_bug(span, "constant in type had error reported as lint");
-            Err(NotConstEvaluatable::Error(reported))
+            Err(ErrorHandled::TooGeneric) => Err(if uv.has_infer_types_or_consts() {
+                NotConstEvaluatable::MentionsInfer
+                } else {
+                NotConstEvaluatable::MentionsParam
+            }),
+            Err(ErrorHandled::Linted) => {
+                let reported =
+                    infcx.tcx.sess.delay_span_bug(span, "constant in type had error reported as lint");
+                Err(NotConstEvaluatable::Error(reported))
+            }
+            Err(ErrorHandled::Reported(e)) => Err(NotConstEvaluatable::Error(e)),
+            Ok(_) => {
+              if uv.substs.has_param_types_or_consts() {
+                  assert!(matches!(infcx.tcx.def_kind(uv.def.did), DefKind::AnonConst));
+                  let mir_body = infcx.tcx.mir_for_ctfe_opt_const_arg(uv.def);
+
+                  if mir_body.is_polymorphic {
+                      let Some(local_def_id) = uv.def.did.as_local() else { return Ok(()) };
+                      tcx.struct_span_lint_hir(
+                          lint::builtin::CONST_EVALUATABLE_UNCHECKED,
+                          tcx.hir().local_def_id_to_hir_id(local_def_id),
+                          span,
+                          |err| {
+                              err.build("cannot use constants which depend on generic parameters in types").emit();
+                        })
+                  }
+              }
+
+              Ok(())
+            },
         }
-        Err(ErrorHandled::Reported(e)) => Err(NotConstEvaluatable::Error(e)),
-        Ok(_) => Ok(()),
     }
 }
 
@@ -247,7 +243,7 @@
         tcx: TyCtxt<'tcx>,
         ct: ty::Const<'tcx>,
     ) -> Result<Option<AbstractConst<'tcx>>, ErrorGuaranteed> {
-        match ct.val() {
+        match ct.kind() {
             ty::ConstKind::Unevaluated(uv) => AbstractConst::new(tcx, uv.shrink()),
             ty::ConstKind::Error(DelaySpanBugEmitted { reported, .. }) => Err(reported),
             _ => Ok(None),
@@ -416,7 +412,7 @@
 
         for n in self.nodes.iter() {
             if let Node::Leaf(ct) = n {
-                if let ty::ConstKind::Unevaluated(ct) = ct.val() {
+                if let ty::ConstKind::Unevaluated(ct) = ct.kind() {
                     // `AbstractConst`s should not contain any promoteds as they require references which
                     // are not allowed.
                     assert_eq!(ct.promoted, None);
@@ -451,15 +447,14 @@
                 self.nodes.push(Node::Leaf(constant))
             }
             &ExprKind::NonHirLiteral { lit , user_ty: _} => {
-                // FIXME Construct a Valtree from this ScalarInt when introducing Valtrees
-                let const_value = ConstValue::Scalar(Scalar::Int(lit));
-                self.nodes.push(Node::Leaf(ty::Const::from_value(self.tcx, const_value, node.ty)))
+                let val = ty::ValTree::from_scalar_int(lit);
+                self.nodes.push(Node::Leaf(ty::Const::from_value(self.tcx, val, node.ty)))
             }
             &ExprKind::NamedConst { def_id, substs, user_ty: _ } => {
                 let uneval = ty::Unevaluated::new(ty::WithOptConstParam::unknown(def_id), substs);
 
                 let constant = self.tcx.mk_const(ty::ConstS {
-                                val: ty::ConstKind::Unevaluated(uneval),
+                                kind: ty::ConstKind::Unevaluated(uneval),
                                 ty: node.ty,
                             });
 
@@ -468,7 +463,7 @@
 
             ExprKind::ConstParam {param, ..} => {
                 let const_param = self.tcx.mk_const(ty::ConstS {
-                        val: ty::ConstKind::Param(*param),
+                        kind: ty::ConstKind::Param(*param),
                         ty: node.ty,
                     });
                 self.nodes.push(Node::Leaf(const_param))
@@ -750,7 +745,7 @@
                     return false;
                 }
 
-                match (a_ct.val(), b_ct.val()) {
+                match (a_ct.kind(), b_ct.kind()) {
                     // We can just unify errors with everything to reduce the amount of
                     // emitted errors here.
                     (ty::ConstKind::Error(_), _) | (_, ty::ConstKind::Error(_)) => true,
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
index 7a3579e..af0803f 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -2,11 +2,10 @@
 pub mod suggestions;
 
 use super::{
-    DerivedObligationCause, EvaluationResult, FulfillmentContext, FulfillmentError,
-    FulfillmentErrorCode, ImplDerivedObligationCause, MismatchedProjectionTypes, Obligation,
-    ObligationCause, ObligationCauseCode, OnUnimplementedDirective, OnUnimplementedNote,
-    OutputTypeParameterMismatch, Overflow, PredicateObligation, SelectionContext, SelectionError,
-    TraitNotObjectSafe,
+    EvaluationResult, FulfillmentContext, FulfillmentError, FulfillmentErrorCode,
+    MismatchedProjectionTypes, Obligation, ObligationCause, ObligationCauseCode,
+    OnUnimplementedDirective, OnUnimplementedNote, OutputTypeParameterMismatch, Overflow,
+    PredicateObligation, SelectionContext, SelectionError, TraitNotObjectSafe,
 };
 
 use crate::infer::error_reporting::{TyCategory, TypeAnnotationNeeded as ErrorCode};
@@ -28,7 +27,7 @@
 use rustc_middle::thir::abstract_const::NotConstEvaluatable;
 use rustc_middle::traits::select::OverflowError;
 use rustc_middle::ty::error::ExpectedFound;
-use rustc_middle::ty::fold::TypeFolder;
+use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable};
 use rustc_middle::ty::{
     self, SubtypePredicate, ToPolyTraitRef, ToPredicate, TraitRef, Ty, TyCtxt, TypeFoldable,
 };
@@ -260,7 +259,7 @@
         let cycle = self.resolve_vars_if_possible(cycle.to_owned());
         assert!(!cycle.is_empty());
 
-        debug!("report_overflow_error_cycle: cycle={:?}", cycle);
+        debug!(?cycle, "report_overflow_error_cycle");
 
         // The 'deepest' obligation is most likely to have a useful
         // cause 'backtrace'
@@ -274,6 +273,7 @@
         error: &SelectionError<'tcx>,
         fallback_has_occurred: bool,
     ) {
+        self.set_tainted_by_errors();
         let tcx = self.tcx;
         let mut span = obligation.cause.span;
 
@@ -417,7 +417,7 @@
                                     span.shrink_to_lo(),
                                     "consider converting the `Option<T>` into a `Result<T, _>` \
                                      using `Option::ok_or` or `Option::ok_or_else`",
-                                    ".ok_or_else(|| /* error value */)".to_string(),
+                                    ".ok_or_else(|| /* error value */)",
                                     Applicability::HasPlaceholders,
                                 );
                             } else if should_convert_result_to_option {
@@ -425,7 +425,7 @@
                                     span.shrink_to_lo(),
                                     "consider converting the `Result<T, _>` into an `Option<T>` \
                                      using `Result::ok`",
-                                    ".ok()".to_string(),
+                                    ".ok()",
                                     Applicability::MachineApplicable,
                                 );
                             }
@@ -684,42 +684,12 @@
                                 let mut code = obligation.cause.code();
                                 let mut trait_pred = trait_predicate;
                                 let mut peeled = false;
-                                loop {
-                                    match &*code {
-                                        ObligationCauseCode::FunctionArgumentObligation {
-                                            parent_code,
-                                            ..
-                                        } => {
-                                            code = &parent_code;
-                                        }
-                                        ObligationCauseCode::ImplDerivedObligation(
-                                            box ImplDerivedObligationCause {
-                                                derived:
-                                                    DerivedObligationCause {
-                                                        parent_code,
-                                                        parent_trait_pred,
-                                                    },
-                                                ..
-                                            },
-                                        )
-                                        | ObligationCauseCode::BuiltinDerivedObligation(
-                                            DerivedObligationCause {
-                                                parent_code,
-                                                parent_trait_pred,
-                                            },
-                                        )
-                                        | ObligationCauseCode::DerivedObligation(
-                                            DerivedObligationCause {
-                                                parent_code,
-                                                parent_trait_pred,
-                                            },
-                                        ) => {
-                                            peeled = true;
-                                            code = &parent_code;
-                                            trait_pred = *parent_trait_pred;
-                                        }
-                                        _ => break,
-                                    };
+                                while let Some((parent_code, parent_trait_pred)) = code.parent() {
+                                    code = parent_code;
+                                    if let Some(parent_trait_pred) = parent_trait_pred {
+                                        trait_pred = parent_trait_pred;
+                                        peeled = true;
+                                    }
                                 }
                                 let def_id = trait_pred.def_id();
                                 // Mention *all* the `impl`s for the *top most* obligation, the
@@ -1114,11 +1084,11 @@
         let hir = self.tcx.hir();
         Some(match node {
             Node::Expr(&hir::Expr {
-                kind: hir::ExprKind::Closure(_, ref _decl, id, span, _),
+                kind: hir::ExprKind::Closure { body, fn_decl_span, .. },
                 ..
             }) => (
-                sm.guess_head_span(span),
-                hir.body(id)
+                sm.guess_head_span(fn_decl_span),
+                hir.body(body)
                     .params
                     .iter()
                     .map(|arg| {
@@ -1415,8 +1385,7 @@
     fn mk_trait_obligation_with_new_self_ty(
         &self,
         param_env: ty::ParamEnv<'tcx>,
-        trait_ref: ty::PolyTraitPredicate<'tcx>,
-        new_self_ty: Ty<'tcx>,
+        trait_ref_and_ty: ty::Binder<'tcx, (ty::TraitPredicate<'tcx>, Ty<'tcx>)>,
     ) -> PredicateObligation<'tcx>;
 
     fn maybe_report_ambiguity(
@@ -1544,6 +1513,7 @@
         }
     }
 
+    #[instrument(level = "debug", skip_all)]
     fn report_projection_error(
         &self,
         obligation: &PredicateObligation<'tcx>,
@@ -1567,7 +1537,7 @@
             let bound_predicate = predicate.kind();
             if let ty::PredicateKind::Projection(data) = bound_predicate.skip_binder() {
                 let mut selcx = SelectionContext::new(self);
-                let (data, _) = self.replace_bound_vars_with_fresh_vars(
+                let data = self.replace_bound_vars_with_fresh_vars(
                     obligation.cause.span,
                     infer::LateBoundRegionConversionTime::HigherRankedType,
                     bound_predicate.rebind(data),
@@ -1582,15 +1552,9 @@
                     &mut obligations,
                 );
 
-                debug!(
-                    "report_projection_error obligation.cause={:?} obligation.param_env={:?}",
-                    obligation.cause, obligation.param_env
-                );
+                debug!(?obligation.cause, ?obligation.param_env);
 
-                debug!(
-                    "report_projection_error normalized_ty={:?} data.ty={:?}",
-                    normalized_ty, data.term,
-                );
+                debug!(?normalized_ty, data.ty = ?data.term);
 
                 let is_normalized_ty_expected = !matches!(
                     obligation.cause.code().peel_derives(),
@@ -1954,14 +1918,11 @@
     fn mk_trait_obligation_with_new_self_ty(
         &self,
         param_env: ty::ParamEnv<'tcx>,
-        trait_ref: ty::PolyTraitPredicate<'tcx>,
-        new_self_ty: Ty<'tcx>,
+        trait_ref_and_ty: ty::Binder<'tcx, (ty::TraitPredicate<'tcx>, Ty<'tcx>)>,
     ) -> PredicateObligation<'tcx> {
-        assert!(!new_self_ty.has_escaping_bound_vars());
-
-        let trait_pred = trait_ref.map_bound_ref(|tr| ty::TraitPredicate {
+        let trait_pred = trait_ref_and_ty.map_bound_ref(|(tr, new_self_ty)| ty::TraitPredicate {
             trait_ref: ty::TraitRef {
-                substs: self.tcx.mk_substs_trait(new_self_ty, &tr.trait_ref.substs[1..]),
+                substs: self.tcx.mk_substs_trait(*new_self_ty, &tr.trait_ref.substs[1..]),
                 ..tr.trait_ref
             },
             ..*tr
@@ -2380,6 +2341,7 @@
         }
     }
 
+    #[instrument(level = "debug", skip_all)]
     fn suggest_unsized_bound_if_applicable(
         &self,
         err: &mut Diagnostic,
@@ -2394,10 +2356,7 @@
         )  else {
             return;
         };
-        debug!(
-            "suggest_unsized_bound_if_applicable: pred={:?} item_def_id={:?} span={:?}",
-            pred, item_def_id, span
-        );
+        debug!(?pred, ?item_def_id, ?span);
 
         let (Some(node), true) = (
             self.tcx.hir().get_if_local(item_def_id),
@@ -2408,6 +2367,7 @@
         self.maybe_suggest_unsized_generics(err, span, node);
     }
 
+    #[instrument(level = "debug", skip_all)]
     fn maybe_suggest_unsized_generics<'hir>(
         &self,
         err: &mut Diagnostic,
@@ -2418,8 +2378,8 @@
             return;
         };
         let sized_trait = self.tcx.lang_items().sized_trait();
-        debug!("maybe_suggest_unsized_generics: generics.params={:?}", generics.params);
-        debug!("maybe_suggest_unsized_generics: generics.predicates={:?}", generics.predicates);
+        debug!(?generics.params);
+        debug!(?generics.predicates);
         let Some(param) = generics.params.iter().find(|param| param.span == span) else {
             return;
         };
@@ -2433,7 +2393,7 @@
         if explicitly_sized {
             return;
         }
-        debug!("maybe_suggest_unsized_generics: param={:?}", param);
+        debug!(?param);
         match node {
             hir::Node::Item(
                 item @ hir::Item {
@@ -2551,7 +2511,7 @@
                 if path.segments.len() == 1 && path.segments[0].ident.name == self.param =>
             {
                 if !self.nested {
-                    debug!("FindTypeParam::visit_ty: ty={:?}", ty);
+                    debug!(?ty, "FindTypeParam::visit_ty");
                     self.invalid_spans.push(ty.span);
                 }
             }
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
index 4263a6f..7c9ee64 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
@@ -103,10 +103,10 @@
                 })
             }),
             hir::Node::Expr(hir::Expr {
-                kind: hir::ExprKind::Closure(_is_move, _, body_id, _, gen_movability),
+                kind: hir::ExprKind::Closure { body, movability, .. },
                 ..
-            }) => self.describe_generator(*body_id).or_else(|| {
-                Some(if gen_movability.is_some() { "an async closure" } else { "a closure" })
+            }) => self.describe_generator(*body).or_else(|| {
+                Some(if movability.is_some() { "an async closure" } else { "a closure" })
             }),
             hir::Node::Expr(hir::Expr { .. }) => {
                 let parent_hid = hir.get_parent_node(hir_id);
@@ -234,7 +234,7 @@
             // Arrays give us `[]`, `[{ty}; _]` and `[{ty}; N]`
             if let ty::Array(aty, len) = self_ty.kind() {
                 flags.push((sym::_Self, Some("[]".to_string())));
-                let len = len.val().try_to_value().and_then(|v| v.try_to_machine_usize(self.tcx));
+                let len = len.kind().try_to_value().and_then(|v| v.try_to_machine_usize(self.tcx));
                 flags.push((sym::_Self, Some(format!("[{}; _]", aty))));
                 if let Some(n) = len {
                     flags.push((sym::_Self, Some(format!("[{}; {}]", aty, n))));
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index d20ba99eb..6c91aa1 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -1,12 +1,13 @@
 use super::{
-    DerivedObligationCause, EvaluationResult, ImplDerivedObligationCause, Obligation,
-    ObligationCause, ObligationCauseCode, PredicateObligation, SelectionContext,
+    EvaluationResult, Obligation, ObligationCause, ObligationCauseCode, PredicateObligation,
+    SelectionContext,
 };
 
 use crate::autoderef::Autoderef;
 use crate::infer::InferCtxt;
-use crate::traits::normalize_projection_type;
+use crate::traits::normalize_to;
 
+use hir::HirId;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_errors::{
@@ -22,8 +23,8 @@
 use rustc_middle::hir::map;
 use rustc_middle::ty::{
     self, suggest_arbitrary_trait_bound, suggest_constraining_type_param, AdtKind, DefIdTree,
-    GeneratorDiagnosticData, GeneratorInteriorTypeCause, Infer, InferTy, ToPredicate, Ty, TyCtxt,
-    TypeFoldable,
+    GeneratorDiagnosticData, GeneratorInteriorTypeCause, Infer, InferTy, IsSuggestable,
+    ToPredicate, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,
 };
 use rustc_middle::ty::{TypeAndMut, TypeckResults};
 use rustc_session::Limit;
@@ -144,11 +145,13 @@
     /// that are live across the yield of this generator
     fn get_generator_interior_types(
         &self,
-    ) -> ty::Binder<'tcx, &Vec<GeneratorInteriorTypeCause<'tcx>>> {
+    ) -> ty::Binder<'tcx, &[GeneratorInteriorTypeCause<'tcx>]> {
         match self {
-            GeneratorData::Local(typeck_result) => typeck_result.generator_interior_types.as_ref(),
+            GeneratorData::Local(typeck_result) => {
+                typeck_result.generator_interior_types.as_deref()
+            }
             GeneratorData::Foreign(generator_diagnostic_data) => {
-                generator_diagnostic_data.generator_interior_types.as_ref()
+                generator_diagnostic_data.generator_interior_types.as_deref()
             }
         }
     }
@@ -320,7 +323,7 @@
 fn predicate_constraint(generics: &hir::Generics<'_>, pred: String) -> (Span, String) {
     (
         generics.tail_span_for_predicate_suggestion(),
-        format!("{} {}", if generics.has_where_clause { "," } else { " where" }, pred,),
+        format!("{} {}", generics.add_where_or_trailing_comma(), pred),
     )
 }
 
@@ -329,35 +332,53 @@
 /// param for cleaner code.
 fn suggest_restriction<'tcx>(
     tcx: TyCtxt<'tcx>,
-    generics: &hir::Generics<'tcx>,
+    hir_id: HirId,
+    hir_generics: &hir::Generics<'tcx>,
     msg: &str,
     err: &mut Diagnostic,
     fn_sig: Option<&hir::FnSig<'_>>,
     projection: Option<&ty::ProjectionTy<'_>>,
     trait_pred: ty::PolyTraitPredicate<'tcx>,
-    super_traits: Option<(&Ident, &hir::GenericBounds<'_>)>,
-) {
     // When we are dealing with a trait, `super_traits` will be `Some`:
     // Given `trait T: A + B + C {}`
     //              -  ^^^^^^^^^ GenericBounds
     //              |
     //              &Ident
-    let span = generics.span_for_predicates_or_empty_place();
-    if span.from_expansion() || span.desugaring_kind().is_some() {
+    super_traits: Option<(&Ident, &hir::GenericBounds<'_>)>,
+) {
+    if hir_generics.where_clause_span.from_expansion()
+        || hir_generics.where_clause_span.desugaring_kind().is_some()
+    {
         return;
     }
+    let Some(item_id) = hir_id.as_owner() else { return; };
+    let generics = tcx.generics_of(item_id);
     // Given `fn foo(t: impl Trait)` where `Trait` requires assoc type `A`...
-    if let Some((bound_str, fn_sig)) =
+    if let Some((param, bound_str, fn_sig)) =
         fn_sig.zip(projection).and_then(|(sig, p)| match p.self_ty().kind() {
             // Shenanigans to get the `Trait` from the `impl Trait`.
             ty::Param(param) => {
-                // `fn foo(t: impl Trait)`
-                //                 ^^^^^ get this string
-                param.name.as_str().strip_prefix("impl").map(|s| (s.trim_start().to_string(), sig))
+                let param_def = generics.type_param(param, tcx);
+                if param_def.kind.is_synthetic() {
+                    let bound_str =
+                        param_def.name.as_str().strip_prefix("impl ")?.trim_start().to_string();
+                    return Some((param_def, bound_str, sig));
+                }
+                None
             }
             _ => None,
         })
     {
+        let type_param_name = hir_generics.params.next_type_param_name(Some(&bound_str));
+        let trait_pred = trait_pred.fold_with(&mut ReplaceImplTraitFolder {
+            tcx,
+            param,
+            replace_ty: ty::ParamTy::new(generics.count() as u32, Symbol::intern(&type_param_name))
+                .to_ty(tcx),
+        });
+        if !trait_pred.is_suggestable(tcx) {
+            return;
+        }
         // We know we have an `impl Trait` that doesn't satisfy a required projection.
 
         // Find all of the occurrences of `impl Trait` for `Trait` in the function arguments'
@@ -366,40 +387,22 @@
         // but instead we choose to suggest replacing all instances of `impl Trait` with `T`
         // where `T: Trait`.
         let mut ty_spans = vec![];
-        let impl_trait_str = format!("impl {}", bound_str);
         for input in fn_sig.decl.inputs {
-            if let hir::TyKind::Path(hir::QPath::Resolved(
-                None,
-                hir::Path { segments: [segment], .. },
-            )) = input.kind
-            {
-                if segment.ident.as_str() == impl_trait_str.as_str() {
-                    // `fn foo(t: impl Trait)`
-                    //            ^^^^^^^^^^ get this to suggest `T` instead
-
-                    // There might be more than one `impl Trait`.
-                    ty_spans.push(input.span);
-                }
-            }
+            ReplaceImplTraitVisitor { ty_spans: &mut ty_spans, param_did: param.def_id }
+                .visit_ty(input);
         }
-
-        let type_param_name = generics.params.next_type_param_name(Some(&bound_str));
         // The type param `T: Trait` we will suggest to introduce.
         let type_param = format!("{}: {}", type_param_name, bound_str);
 
-        // FIXME: modify the `trait_pred` instead of string shenanigans.
-        // Turn `<impl Trait as Foo>::Bar: Qux` into `<T as Foo>::Bar: Qux`.
-        let pred = trait_pred.to_predicate(tcx).to_string();
-        let pred = pred.replace(&impl_trait_str, &type_param_name);
         let mut sugg = vec![
-            if let Some(span) = generics.span_for_param_suggestion() {
+            if let Some(span) = hir_generics.span_for_param_suggestion() {
                 (span, format!(", {}", type_param))
             } else {
-                (generics.span, format!("<{}>", type_param))
+                (hir_generics.span, format!("<{}>", type_param))
             },
             // `fn foo(t: impl Trait)`
             //                       ^ suggest `where <T as Trait>::A: Bound`
-            predicate_constraint(generics, pred),
+            predicate_constraint(hir_generics, trait_pred.to_predicate(tcx).to_string()),
         ];
         sugg.extend(ty_spans.into_iter().map(|s| (s, type_param_name.to_string())));
 
@@ -412,15 +415,20 @@
             Applicability::MaybeIncorrect,
         );
     } else {
+        if !trait_pred.is_suggestable(tcx) {
+            return;
+        }
         // Trivial case: `T` needs an extra bound: `T: Bound`.
         let (sp, suggestion) = match (
-            generics
+            hir_generics
                 .params
                 .iter()
                 .find(|p| !matches!(p.kind, hir::GenericParamKind::Type { synthetic: true, .. })),
             super_traits,
         ) {
-            (_, None) => predicate_constraint(generics, trait_pred.to_predicate(tcx).to_string()),
+            (_, None) => {
+                predicate_constraint(hir_generics, trait_pred.to_predicate(tcx).to_string())
+            }
             (None, Some((ident, []))) => (
                 ident.span.shrink_to_hi(),
                 format!(": {}", trait_pred.print_modifiers_and_trait_path()),
@@ -430,7 +438,7 @@
                 format!(" + {}", trait_pred.print_modifiers_and_trait_path()),
             ),
             (Some(_), Some((_, []))) => (
-                generics.span.shrink_to_hi(),
+                hir_generics.span.shrink_to_hi(),
                 format!(": {}", trait_pred.print_modifiers_and_trait_path()),
             ),
         };
@@ -451,6 +459,8 @@
         trait_pred: ty::PolyTraitPredicate<'tcx>,
         body_id: hir::HirId,
     ) {
+        let trait_pred = self.resolve_numeric_literals_with_default(trait_pred);
+
         let self_ty = trait_pred.skip_binder().self_ty();
         let (param_ty, projection) = match self_ty.kind() {
             ty::Param(_) => (true, None),
@@ -472,6 +482,7 @@
                     // Restricting `Self` for a single method.
                     suggest_restriction(
                         self.tcx,
+                        hir_id,
                         &generics,
                         "`Self`",
                         err,
@@ -491,7 +502,8 @@
                     assert!(param_ty);
                     // Restricting `Self` for a single method.
                     suggest_restriction(
-                        self.tcx, &generics, "`Self`", err, None, projection, trait_pred, None,
+                        self.tcx, hir_id, &generics, "`Self`", err, None, projection, trait_pred,
+                        None,
                     );
                     return;
                 }
@@ -512,6 +524,7 @@
                     // Missing restriction on associated type of type parameter (unmet projection).
                     suggest_restriction(
                         self.tcx,
+                        hir_id,
                         &generics,
                         "the associated type",
                         err,
@@ -531,6 +544,7 @@
                     // Missing restriction on associated type of type parameter (unmet projection).
                     suggest_restriction(
                         self.tcx,
+                        hir_id,
                         &generics,
                         "the associated type",
                         err,
@@ -559,6 +573,20 @@
                 | hir::Node::ImplItem(hir::ImplItem { generics, .. })
                     if param_ty =>
                 {
+                    // We skip the 0'th subst (self) because we do not want
+                    // to consider the predicate as not suggestible if the
+                    // self type is an arg position `impl Trait` -- instead,
+                    // we handle that by adding ` + Bound` below.
+                    // FIXME(compiler-errors): It would be nice to do the same
+                    // this that we do in `suggest_restriction` and pull the
+                    // `impl Trait` into a new generic if it shows up somewhere
+                    // else in the predicate.
+                    if !trait_pred.skip_binder().trait_ref.substs[1..]
+                        .iter()
+                        .all(|g| g.is_suggestable(self.tcx))
+                    {
+                        return;
+                    }
                     // Missing generic type parameter bound.
                     let param_name = self_ty.to_string();
                     let constraint = with_no_trimmed_paths!(
@@ -590,9 +618,7 @@
                     ..
                 }) if !param_ty => {
                     // Missing generic type parameter bound.
-                    let param_name = self_ty.to_string();
-                    let constraint = trait_pred.print_modifiers_and_trait_path().to_string();
-                    if suggest_arbitrary_trait_bound(generics, &mut err, &param_name, &constraint) {
+                    if suggest_arbitrary_trait_bound(self.tcx, generics, &mut err, trait_pred) {
                         return;
                     }
                 }
@@ -623,39 +649,26 @@
         let span = obligation.cause.span;
         let mut real_trait_pred = trait_pred;
         let mut code = obligation.cause.code();
-        loop {
-            match &code {
-                ObligationCauseCode::FunctionArgumentObligation { parent_code, .. } => {
-                    code = &parent_code;
-                }
-                ObligationCauseCode::ImplDerivedObligation(box ImplDerivedObligationCause {
-                    derived: DerivedObligationCause { parent_code, parent_trait_pred },
-                    ..
-                })
-                | ObligationCauseCode::BuiltinDerivedObligation(DerivedObligationCause {
-                    parent_code,
-                    parent_trait_pred,
-                })
-                | ObligationCauseCode::DerivedObligation(DerivedObligationCause {
-                    parent_code,
-                    parent_trait_pred,
-                }) => {
-                    code = &parent_code;
-                    real_trait_pred = *parent_trait_pred;
-                }
-                _ => break,
-            };
-            let Some(real_ty) = real_trait_pred.self_ty().no_bound_vars() else {
-                continue;
-            };
+        while let Some((parent_code, parent_trait_pred)) = code.parent() {
+            code = parent_code;
+            if let Some(parent_trait_pred) = parent_trait_pred {
+                real_trait_pred = parent_trait_pred;
+            }
+
+            // Skipping binder here, remapping below
+            let real_ty = real_trait_pred.self_ty().skip_binder();
 
             if let ty::Ref(region, base_ty, mutbl) = *real_ty.kind() {
                 let mut autoderef = Autoderef::new(self, param_env, body_id, span, base_ty, span);
                 if let Some(steps) = autoderef.find_map(|(ty, steps)| {
                     // Re-add the `&`
                     let ty = self.tcx.mk_ref(region, TypeAndMut { ty, mutbl });
-                    let obligation =
-                        self.mk_trait_obligation_with_new_self_ty(param_env, real_trait_pred, ty);
+
+                    // Remapping bound vars here
+                    let real_trait_pred_and_ty =
+                        real_trait_pred.map_bound(|inner_trait_pred| (inner_trait_pred, ty));
+                    let obligation = self
+                        .mk_trait_obligation_with_new_self_ty(param_env, real_trait_pred_and_ty);
                     Some(steps).filter(|_| self.predicate_may_hold(&obligation))
                 }) {
                     if steps > 0 {
@@ -676,16 +689,19 @@
                     }
                 } else if real_trait_pred != trait_pred {
                     // This branch addresses #87437.
+
+                    // Remapping bound vars here
+                    let real_trait_pred_and_base_ty =
+                        real_trait_pred.map_bound(|inner_trait_pred| (inner_trait_pred, base_ty));
                     let obligation = self.mk_trait_obligation_with_new_self_ty(
                         param_env,
-                        real_trait_pred,
-                        base_ty,
+                        real_trait_pred_and_base_ty,
                     );
                     if self.predicate_may_hold(&obligation) {
                         err.span_suggestion_verbose(
                             span.shrink_to_lo(),
                             "consider dereferencing here",
-                            "*".to_string(),
+                            "*",
                             Applicability::MachineApplicable,
                         );
                         return true;
@@ -737,9 +753,8 @@
         err: &mut Diagnostic,
         trait_pred: ty::PolyTraitPredicate<'tcx>,
     ) -> bool {
-        let Some(self_ty) = trait_pred.self_ty().no_bound_vars() else {
-            return false;
-        };
+        // Skipping binder here, remapping below
+        let self_ty = trait_pred.self_ty().skip_binder();
 
         let (def_id, output_ty, callable) = match *self_ty.kind() {
             ty::Closure(def_id, substs) => (def_id, substs.as_closure().sig().output(), "closure"),
@@ -748,19 +763,21 @@
         };
         let msg = format!("use parentheses to call the {}", callable);
 
-        // `mk_trait_obligation_with_new_self_ty` only works for types with no escaping bound
-        // variables, so bail out if we have any.
-        let Some(output_ty) = output_ty.no_bound_vars() else {
-            return false;
-        };
+        // "We should really create a single list of bound vars from the combined vars
+        // from the predicate and function, but instead we just liberate the function bound vars"
+        let output_ty = self.tcx.liberate_late_bound_regions(def_id, output_ty);
+
+        // Remapping bound vars here
+        let trait_pred_and_self = trait_pred.map_bound(|trait_pred| (trait_pred, output_ty));
 
         let new_obligation =
-            self.mk_trait_obligation_with_new_self_ty(obligation.param_env, trait_pred, output_ty);
+            self.mk_trait_obligation_with_new_self_ty(obligation.param_env, trait_pred_and_self);
 
         match self.evaluate_obligation(&new_obligation) {
             Ok(
                 EvaluationResult::EvaluatedToOk
                 | EvaluationResult::EvaluatedToOkModuloRegions
+                | EvaluationResult::EvaluatedToOkModuloOpaqueTypes
                 | EvaluationResult::EvaluatedToAmbig,
             ) => {}
             _ => return false,
@@ -769,14 +786,14 @@
         // Get the name of the callable and the arguments to be used in the suggestion.
         let (snippet, sugg) = match hir.get_if_local(def_id) {
             Some(hir::Node::Expr(hir::Expr {
-                kind: hir::ExprKind::Closure(_, decl, _, span, ..),
+                kind: hir::ExprKind::Closure { fn_decl, fn_decl_span, .. },
                 ..
             })) => {
-                err.span_label(*span, "consider calling this closure");
+                err.span_label(*fn_decl_span, "consider calling this closure");
                 let Some(name) = self.get_closure_name(def_id, err, &msg) else {
                     return false;
                 };
-                let args = decl.inputs.iter().map(|_| "_").collect::<Vec<_>>().join(", ");
+                let args = fn_decl.inputs.iter().map(|_| "_").collect::<Vec<_>>().join(", ");
                 let sugg = format!("({})", args);
                 (format!("{}{}", name, sugg), sugg)
             }
@@ -859,96 +876,97 @@
         let param_env = obligation.param_env;
 
         // Try to apply the original trait binding obligation by borrowing.
-        let mut try_borrowing = |old_pred: ty::PolyTraitPredicate<'tcx>,
-                                 blacklist: &[DefId]|
-         -> bool {
-            if blacklist.contains(&old_pred.def_id()) {
-                return false;
-            }
-
-            // This is a quick fix to resolve an ICE (#96223).
-            // This change should probably be deeper.
-            // As suggested by @jackh726, `mk_trait_obligation_with_new_self_ty` could take a `Binder<(TraitRef, Ty)>
-            // instead of `Binder<Ty>` leading to some changes to its call places.
-            let Some(orig_ty) = old_pred.self_ty().no_bound_vars() else {
-                return false;
-            };
-            let mk_result = |new_ty| {
-                let obligation =
-                    self.mk_trait_obligation_with_new_self_ty(param_env, old_pred, new_ty);
-                self.predicate_must_hold_modulo_regions(&obligation)
-            };
-            let imm_result = mk_result(self.tcx.mk_imm_ref(self.tcx.lifetimes.re_static, orig_ty));
-            let mut_result = mk_result(self.tcx.mk_mut_ref(self.tcx.lifetimes.re_static, orig_ty));
-
-            if imm_result || mut_result {
-                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
-                    // might solve the problem. In cases like this, the important part is the
-                    // 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",
-                        orig_ty,
-                        old_pred.print_modifiers_and_trait_path(),
-                    );
-                    if has_custom_message {
-                        err.note(&msg);
-                    } else {
-                        err.message =
-                            vec![(rustc_errors::DiagnosticMessage::Str(msg), Style::NoStyle)];
-                    }
-                    if snippet.starts_with('&') {
-                        // This is already a literal borrow and the obligation is failing
-                        // somewhere else in the obligation chain. Do not suggest non-sense.
-                        return false;
-                    }
-                    err.span_label(
-                        span,
-                        &format!(
-                            "expected an implementor of trait `{}`",
-                            old_pred.print_modifiers_and_trait_path(),
-                        ),
-                    );
-
-                    // This if is to prevent a special edge-case
-                    if matches!(
-                        span.ctxt().outer_expn_data().kind,
-                        ExpnKind::Root | ExpnKind::Desugaring(DesugaringKind::ForLoop)
-                    ) {
-                        // We don't want a borrowing suggestion on the fields in structs,
-                        // ```
-                        // struct Foo {
-                        //  the_foos: Vec<Foo>
-                        // }
-                        // ```
-
-                        if imm_result && mut_result {
-                            err.span_suggestions(
-                                span.shrink_to_lo(),
-                                "consider borrowing here",
-                                ["&".to_string(), "&mut ".to_string()].into_iter(),
-                                Applicability::MaybeIncorrect,
-                            );
-                        } else {
-                            err.span_suggestion_verbose(
-                                span.shrink_to_lo(),
-                                &format!(
-                                    "consider{} borrowing here",
-                                    if mut_result { " mutably" } else { "" }
-                                ),
-                                format!("&{}", if mut_result { "mut " } else { "" }),
-                                Applicability::MaybeIncorrect,
-                            );
-                        }
-                    }
-                    return true;
+        let mut try_borrowing =
+            |old_pred: ty::PolyTraitPredicate<'tcx>, blacklist: &[DefId]| -> bool {
+                if blacklist.contains(&old_pred.def_id()) {
+                    return false;
                 }
-            }
-            return false;
-        };
+                // We map bounds to `&T` and `&mut T`
+                let trait_pred_and_imm_ref = old_pred.map_bound(|trait_pred| {
+                    (
+                        trait_pred,
+                        self.tcx.mk_imm_ref(self.tcx.lifetimes.re_static, trait_pred.self_ty()),
+                    )
+                });
+                let trait_pred_and_mut_ref = old_pred.map_bound(|trait_pred| {
+                    (
+                        trait_pred,
+                        self.tcx.mk_mut_ref(self.tcx.lifetimes.re_static, trait_pred.self_ty()),
+                    )
+                });
+
+                let mk_result = |trait_pred_and_new_ty| {
+                    let obligation =
+                        self.mk_trait_obligation_with_new_self_ty(param_env, trait_pred_and_new_ty);
+                    self.predicate_must_hold_modulo_regions(&obligation)
+                };
+                let imm_result = mk_result(trait_pred_and_imm_ref);
+                let mut_result = mk_result(trait_pred_and_mut_ref);
+
+                if imm_result || mut_result {
+                    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
+                        // might solve the problem. In cases like this, the important part is the
+                        // 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", old_pred);
+                        if has_custom_message {
+                            err.note(&msg);
+                        } else {
+                            err.message =
+                                vec![(rustc_errors::DiagnosticMessage::Str(msg), Style::NoStyle)];
+                        }
+                        if snippet.starts_with('&') {
+                            // This is already a literal borrow and the obligation is failing
+                            // somewhere else in the obligation chain. Do not suggest non-sense.
+                            return false;
+                        }
+                        err.span_label(
+                            span,
+                            &format!(
+                                "expected an implementor of trait `{}`",
+                                old_pred.print_modifiers_and_trait_path(),
+                            ),
+                        );
+
+                        // This if is to prevent a special edge-case
+                        if matches!(
+                            span.ctxt().outer_expn_data().kind,
+                            ExpnKind::Root | ExpnKind::Desugaring(DesugaringKind::ForLoop)
+                        ) {
+                            // We don't want a borrowing suggestion on the fields in structs,
+                            // ```
+                            // struct Foo {
+                            //  the_foos: Vec<Foo>
+                            // }
+                            // ```
+
+                            if imm_result && mut_result {
+                                err.span_suggestions(
+                                    span.shrink_to_lo(),
+                                    "consider borrowing here",
+                                    ["&".to_string(), "&mut ".to_string()].into_iter(),
+                                    Applicability::MaybeIncorrect,
+                                );
+                            } else {
+                                err.span_suggestion_verbose(
+                                    span.shrink_to_lo(),
+                                    &format!(
+                                        "consider{} borrowing here",
+                                        if mut_result { " mutably" } else { "" }
+                                    ),
+                                    format!("&{}", if mut_result { "mut " } else { "" }),
+                                    Applicability::MaybeIncorrect,
+                                );
+                            }
+                        }
+                        return true;
+                    }
+                }
+                return false;
+            };
 
         if let ObligationCauseCode::ImplDerivedObligation(cause) = &*code {
             try_borrowing(cause.derived.parent_trait_pred, &[])
@@ -985,7 +1003,7 @@
             &format!(
                 "consider borrowing the value, since `&{self_ty}` can be coerced into `{object_ty}`"
             ),
-            "&".to_string(),
+            "&",
             Applicability::MaybeIncorrect,
         );
     }
@@ -1009,9 +1027,8 @@
                 return false;
             }
 
-            let Some(mut suggested_ty) = trait_pred.self_ty().no_bound_vars() else {
-                return false;
-            };
+            // Skipping binder here, remapping below
+            let mut suggested_ty = trait_pred.self_ty().skip_binder();
 
             for refs_remaining in 0..refs_number {
                 let ty::Ref(_, inner_ty, _) = suggested_ty.kind() else {
@@ -1019,10 +1036,13 @@
                 };
                 suggested_ty = *inner_ty;
 
+                // Remapping bound vars here
+                let trait_pred_and_suggested_ty =
+                    trait_pred.map_bound(|trait_pred| (trait_pred, suggested_ty));
+
                 let new_obligation = self.mk_trait_obligation_with_new_self_ty(
                     obligation.param_env,
-                    trait_pred,
-                    suggested_ty,
+                    trait_pred_and_suggested_ty,
                 );
 
                 if self.predicate_may_hold(&new_obligation) {
@@ -1040,12 +1060,7 @@
                         format!("consider removing {} leading `&`-references", remove_refs)
                     };
 
-                    err.span_suggestion_short(
-                        sp,
-                        &msg,
-                        String::new(),
-                        Applicability::MachineApplicable,
-                    );
+                    err.span_suggestion_short(sp, &msg, "", Applicability::MachineApplicable);
                     suggested = true;
                     break;
                 }
@@ -1068,7 +1083,7 @@
                     err.span_suggestion_verbose(
                         expr.span.shrink_to_hi().with_hi(span.hi()),
                         "remove the `.await`",
-                        String::new(),
+                        "",
                         Applicability::MachineApplicable,
                     );
                     // FIXME: account for associated `async fn`s.
@@ -1096,14 +1111,14 @@
                                 err.span_suggestion_verbose(
                                     span.shrink_to_lo(),
                                     &msg,
-                                    "async ".to_string(),
+                                    "async ",
                                     Applicability::MaybeIncorrect,
                                 );
                             } else {
                                 err.span_suggestion_verbose(
                                     vis_span.shrink_to_hi(),
                                     &msg,
-                                    " async".to_string(),
+                                    " async",
                                     Applicability::MaybeIncorrect,
                                 );
                             }
@@ -1142,26 +1157,21 @@
                 return;
             }
 
+            // Skipping binder here, remapping below
             if let ty::Ref(region, t_type, mutability) = *trait_pred.skip_binder().self_ty().kind()
             {
-                if region.is_late_bound() || t_type.has_escaping_bound_vars() {
-                    // Avoid debug assertion in `mk_obligation_for_def_id`.
-                    //
-                    // If the self type has escaping bound vars then it's not
-                    // going to be the type of an expression, so the suggestion
-                    // probably won't apply anyway.
-                    return;
-                }
-
                 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),
                 };
 
+                // Remapping bound vars here
+                let trait_pred_and_suggested_ty =
+                    trait_pred.map_bound(|trait_pred| (trait_pred, suggested_ty));
+
                 let new_obligation = self.mk_trait_obligation_with_new_self_ty(
                     obligation.param_env,
-                    trait_pred,
-                    suggested_ty,
+                    trait_pred_and_suggested_ty,
                 );
                 let suggested_ty_would_satisfy_obligation = self
                     .evaluate_obligation_no_overflow(&new_obligation)
@@ -1176,7 +1186,7 @@
                         err.span_suggestion_verbose(
                             sp,
                             "consider changing this borrow's mutability",
-                            "&mut ".to_string(),
+                            "&mut ",
                             Applicability::MachineApplicable,
                         );
                     } else {
@@ -1212,7 +1222,9 @@
             // Only suggest this if the expression behind the semicolon implements the predicate
             && let Some(typeck_results) = self.in_progress_typeck_results
             && let Some(ty) = typeck_results.borrow().expr_ty_opt(expr)
-            && self.predicate_may_hold(&self.mk_trait_obligation_with_new_self_ty(obligation.param_env, trait_pred, ty))
+            && self.predicate_may_hold(&self.mk_trait_obligation_with_new_self_ty(
+                obligation.param_env, trait_pred.map_bound(|trait_pred| (trait_pred, ty))
+            ))
         {
             err.span_label(
                 expr.span,
@@ -1225,7 +1237,7 @@
             err.span_suggestion(
                 self.tcx.sess.source_map().end_point(stmt.span),
                 "remove this semicolon",
-                String::new(),
+                "",
                 Applicability::MachineApplicable
             );
             return true;
@@ -1498,7 +1510,7 @@
         expected_ref: ty::PolyTraitRef<'tcx>,
         found: ty::PolyTraitRef<'tcx>,
     ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
-        crate fn build_fn_sig_string<'tcx>(
+        pub(crate) fn build_fn_sig_string<'tcx>(
             tcx: TyCtxt<'tcx>,
             trait_ref: ty::PolyTraitRef<'tcx>,
         ) -> String {
@@ -1617,16 +1629,12 @@
     /// ```
     ///
     /// Returns `true` if an async-await specific note was added to the diagnostic.
+    #[instrument(level = "debug", skip_all, fields(?obligation.predicate, ?obligation.cause.span))]
     fn maybe_note_obligation_cause_for_async_await(
         &self,
         err: &mut Diagnostic,
         obligation: &PredicateObligation<'tcx>,
     ) -> bool {
-        debug!(
-            "maybe_note_obligation_cause_for_async_await: obligation.predicate={:?} \
-                obligation.cause.span={:?}",
-            obligation.predicate, obligation.cause.span
-        );
         let hir = self.tcx.hir();
 
         // Attempt to detect an async-await error by looking at the obligation causes, looking
@@ -1666,18 +1674,17 @@
         let mut seen_upvar_tys_infer_tuple = false;
 
         while let Some(code) = next_code {
-            debug!("maybe_note_obligation_cause_for_async_await: code={:?}", code);
+            debug!(?code);
             match code {
                 ObligationCauseCode::FunctionArgumentObligation { parent_code, .. } => {
-                    next_code = Some(parent_code.as_ref());
+                    next_code = Some(parent_code);
                 }
                 ObligationCauseCode::ImplDerivedObligation(cause) => {
                     let ty = cause.derived.parent_trait_pred.skip_binder().self_ty();
                     debug!(
-                        "maybe_note_obligation_cause_for_async_await: ImplDerived \
-                         parent_trait_ref={:?} self_ty.kind={:?}",
-                        cause.derived.parent_trait_pred,
-                        ty.kind()
+                        parent_trait_ref = ?cause.derived.parent_trait_pred,
+                        self_ty.kind = ?ty.kind(),
+                        "ImplDerived",
                     );
 
                     match *ty.kind() {
@@ -1700,16 +1707,14 @@
                         _ => {}
                     }
 
-                    next_code = Some(cause.derived.parent_code.as_ref());
+                    next_code = Some(&cause.derived.parent_code);
                 }
                 ObligationCauseCode::DerivedObligation(derived_obligation)
                 | ObligationCauseCode::BuiltinDerivedObligation(derived_obligation) => {
                     let ty = derived_obligation.parent_trait_pred.skip_binder().self_ty();
                     debug!(
-                        "maybe_note_obligation_cause_for_async_await: \
-                         parent_trait_ref={:?} self_ty.kind={:?}",
-                        derived_obligation.parent_trait_pred,
-                        ty.kind()
+                        parent_trait_ref = ?derived_obligation.parent_trait_pred,
+                        self_ty.kind = ?ty.kind(),
                     );
 
                     match *ty.kind() {
@@ -1732,14 +1737,14 @@
                         _ => {}
                     }
 
-                    next_code = Some(derived_obligation.parent_code.as_ref());
+                    next_code = Some(&derived_obligation.parent_code);
                 }
                 _ => break,
             }
         }
 
         // Only continue if a generator was found.
-        debug!(?generator, ?trait_ref, ?target_ty, "maybe_note_obligation_cause_for_async_await");
+        debug!(?generator, ?trait_ref, ?target_ty);
         let (Some(generator_did), Some(trait_ref), Some(target_ty)) = (generator, trait_ref, target_ty) else {
             return false;
         };
@@ -1749,12 +1754,10 @@
         let in_progress_typeck_results = self.in_progress_typeck_results.map(|t| t.borrow());
         let generator_did_root = self.tcx.typeck_root_def_id(generator_did);
         debug!(
-            "maybe_note_obligation_cause_for_async_await: generator_did={:?} \
-             generator_did_root={:?} in_progress_typeck_results.hir_owner={:?} span={:?}",
-            generator_did,
-            generator_did_root,
-            in_progress_typeck_results.as_ref().map(|t| t.hir_owner),
-            span
+            ?generator_did,
+            ?generator_did_root,
+            in_progress_typeck_results.hir_owner = ?in_progress_typeck_results.as_ref().map(|t| t.hir_owner),
+            ?span,
         );
 
         let generator_body = generator_did
@@ -1777,7 +1780,7 @@
         if let Some(body) = generator_body {
             visitor.visit_body(body);
         }
-        debug!("maybe_note_obligation_cause_for_async_await: awaits = {:?}", visitor.awaits);
+        debug!(awaits = ?visitor.awaits);
 
         // Look for a type inside the generator interior that matches the target type to get
         // a span.
@@ -1798,11 +1801,7 @@
             let ty_erased = self.tcx.erase_late_bound_regions(ty);
             let ty_erased = self.tcx.erase_regions(ty_erased);
             let eq = ty_erased == target_ty_erased;
-            debug!(
-                "maybe_note_obligation_cause_for_async_await: ty_erased={:?} \
-                    target_ty_erased={:?} eq={:?}",
-                ty_erased, target_ty_erased, eq
-            );
+            debug!(?ty_erased, ?target_ty_erased, ?eq);
             eq
         };
 
@@ -1877,6 +1876,7 @@
 
     /// Unconditionally adds the diagnostic note described in
     /// `maybe_note_obligation_cause_for_async_await`'s documentation comment.
+    #[instrument(level = "debug", skip_all)]
     fn note_obligation_cause_for_async_await(
         &self,
         err: &mut Diagnostic,
@@ -2026,8 +2026,9 @@
                     } else {
                         // Look at the last interior type to get a span for the `.await`.
                         debug!(
-                            "note_obligation_cause_for_async_await generator_interior_types: {:#?}",
-                            typeck_results.as_ref().map(|t| &t.generator_interior_types)
+                            generator_interior_types = ?format_args!(
+                                "{:#?}", typeck_results.as_ref().map(|t| &t.generator_interior_types)
+                            ),
                         );
                         explain_yield(interior_span, yield_span, scope_span);
                     }
@@ -2062,7 +2063,7 @@
                             // bar(Foo(std::ptr::null())).await;
                             //     ^^^^^^^^^^^^^^^^^^^^^ raw-ptr `*T` created inside this struct ctor.
                             // ```
-                            debug!("parent_def_kind: {:?}", self.tcx.def_kind(parent_did));
+                            debug!(parent_def_kind = ?self.tcx.def_kind(parent_did));
                             let is_raw_borrow_inside_fn_like_call =
                                 match self.tcx.def_kind(parent_did) {
                                     DefKind::Fn | DefKind::Ctor(..) => target_ty.is_unsafe_ptr(),
@@ -2120,7 +2121,7 @@
 
         // Add a note for the item obligation that remains - normally a note pointing to the
         // bound that introduced the obligation (e.g. `T: Send`).
-        debug!("note_obligation_cause_for_async_await: next_code={:?}", next_code);
+        debug!(?next_code);
         self.note_obligation_cause_code(
             err,
             &obligation.predicate,
@@ -2259,7 +2260,7 @@
                         err.span_suggestion_verbose(
                             span.shrink_to_lo(),
                             "consider borrowing here",
-                            "&".to_owned(),
+                            "&",
                             Applicability::MachineApplicable,
                         );
                         err.note("all local variables must have a statically known size");
@@ -2269,7 +2270,7 @@
                             param.ty_span.shrink_to_lo(),
                             "function arguments must have a statically known size, borrowed types \
                             always have a known size",
-                            "&".to_owned(),
+                            "&",
                             Applicability::MachineApplicable,
                         );
                     }
@@ -2287,7 +2288,7 @@
                         span.shrink_to_lo(),
                         "function arguments must have a statically known size, borrowed types \
                          always have a known size",
-                        "&".to_string(),
+                        "&",
                         Applicability::MachineApplicable,
                     );
                 } else {
@@ -2342,7 +2343,7 @@
                 err.span_suggestion(
                     span.shrink_to_lo(),
                     "borrowed types always have a statically known size",
-                    "&".to_string(),
+                    "&",
                     Applicability::MachineApplicable,
                 );
                 err.multipart_suggestion(
@@ -2382,29 +2383,91 @@
                 let is_upvar_tys_infer_tuple = if !matches!(ty.kind(), ty::Tuple(..)) {
                     false
                 } else {
-                    if let ObligationCauseCode::BuiltinDerivedObligation(ref data) =
-                        *data.parent_code
+                    if let ObligationCauseCode::BuiltinDerivedObligation(data) = &*data.parent_code
                     {
                         let parent_trait_ref =
                             self.resolve_vars_if_possible(data.parent_trait_pred);
-                        let ty = parent_trait_ref.skip_binder().self_ty();
-                        matches!(ty.kind(), ty::Generator(..))
-                            || matches!(ty.kind(), ty::Closure(..))
+                        let nested_ty = parent_trait_ref.skip_binder().self_ty();
+                        matches!(nested_ty.kind(), ty::Generator(..))
+                            || matches!(nested_ty.kind(), ty::Closure(..))
                     } else {
                         false
                     }
                 };
 
+                let from_generator = tcx.lang_items().from_generator_fn().unwrap();
+
                 // Don't print the tuple of capture types
-                if !is_upvar_tys_infer_tuple {
-                    let msg = format!("required because it appears within the type `{}`", ty);
-                    match ty.kind() {
-                        ty::Adt(def, _) => match self.tcx.opt_item_ident(def.did()) {
-                            Some(ident) => err.span_note(ident.span, &msg),
-                            None => err.note(&msg),
-                        },
-                        _ => err.note(&msg),
-                    };
+                'print: {
+                    if !is_upvar_tys_infer_tuple {
+                        let msg = format!("required because it appears within the type `{}`", ty);
+                        match ty.kind() {
+                            ty::Adt(def, _) => {
+                                // `gen_future` is used in all async functions; it doesn't add any additional info.
+                                if self.tcx.is_diagnostic_item(sym::gen_future, def.did()) {
+                                    break 'print;
+                                }
+                                match self.tcx.opt_item_ident(def.did()) {
+                                    Some(ident) => err.span_note(ident.span, &msg),
+                                    None => err.note(&msg),
+                                }
+                            }
+                            ty::Opaque(def_id, _) => {
+                                // Avoid printing the future from `core::future::from_generator`, it's not helpful
+                                if tcx.parent(*def_id) == from_generator {
+                                    break 'print;
+                                }
+
+                                // If the previous type is `from_generator`, this is the future generated by the body of an async function.
+                                // Avoid printing it twice (it was already printed in the `ty::Generator` arm below).
+                                let is_future = tcx.ty_is_opaque_future(ty);
+                                debug!(
+                                    ?obligated_types,
+                                    ?is_future,
+                                    "note_obligation_cause_code: check for async fn"
+                                );
+                                if is_future
+                                    && obligated_types.last().map_or(false, |ty| match ty.kind() {
+                                        ty::Opaque(last_def_id, _) => {
+                                            tcx.parent(*last_def_id) == from_generator
+                                        }
+                                        _ => false,
+                                    })
+                                {
+                                    break 'print;
+                                }
+                                err.span_note(self.tcx.def_span(def_id), &msg)
+                            }
+                            ty::GeneratorWitness(bound_tys) => {
+                                use std::fmt::Write;
+
+                                // FIXME: this is kind of an unusual format for rustc, can we make it more clear?
+                                // Maybe we should just remove this note altogether?
+                                // FIXME: only print types which don't meet the trait requirement
+                                let mut msg =
+                                    "required because it captures the following types: ".to_owned();
+                                for ty in bound_tys.skip_binder() {
+                                    write!(msg, "`{}`, ", ty).unwrap();
+                                }
+                                err.note(msg.trim_end_matches(", "))
+                            }
+                            ty::Generator(def_id, _, _) => {
+                                let sp = self.tcx.def_span(def_id);
+
+                                // Special-case this to say "async block" instead of `[static generator]`.
+                                let kind = tcx.generator_kind(def_id).unwrap();
+                                err.span_note(
+                                    sp,
+                                    &format!("required because it's used within this {}", kind),
+                                )
+                            }
+                            ty::Closure(def_id, _) => err.span_note(
+                                self.tcx.def_span(def_id),
+                                &format!("required because it's used within this closure"),
+                            ),
+                            _ => err.note(&msg),
+                        };
+                    }
                 }
 
                 obligated_types.push(ty);
@@ -2428,7 +2491,7 @@
                             err,
                             &parent_predicate,
                             param_env,
-                            &cause_code.peel_derives(),
+                            cause_code.peel_derives(),
                             obligated_types,
                             seen_requirements,
                         )
@@ -2662,6 +2725,15 @@
                     err.help("add `#![feature(trivial_bounds)]` to the crate attributes to enable");
                 }
             }
+            ObligationCauseCode::OpaqueReturnType(expr_info) => {
+                if let Some((expr_ty, expr_span)) = expr_info {
+                    let expr_ty = self.resolve_vars_if_possible(expr_ty);
+                    err.span_label(
+                        expr_span,
+                        format!("return type was inferred to be `{expr_ty}` here"),
+                    );
+                }
+            }
         }
     }
 
@@ -2678,6 +2750,9 @@
         ));
     }
 
+    #[instrument(
+        level = "debug", skip(self, err), fields(trait_pred.self_ty = ?trait_pred.self_ty())
+    )]
     fn suggest_await_before_try(
         &self,
         err: &mut Diagnostic,
@@ -2685,13 +2760,6 @@
         trait_pred: ty::PolyTraitPredicate<'tcx>,
         span: Span,
     ) {
-        debug!(
-            "suggest_await_before_try: obligation={:?}, span={:?}, trait_pred={:?}, trait_pred_self_ty={:?}",
-            obligation,
-            span,
-            trait_pred,
-            trait_pred.self_ty()
-        );
         let body_hir_id = obligation.cause.body_id;
         let item_id = self.tcx.hir().get_parent_node(body_hir_id);
 
@@ -2701,63 +2769,49 @@
                 let future_trait = self.tcx.require_lang_item(LangItem::Future, None);
 
                 let self_ty = self.resolve_vars_if_possible(trait_pred.self_ty());
-
-                // Do not check on infer_types to avoid panic in evaluate_obligation.
-                if self_ty.has_infer_types() {
-                    return;
-                }
-                let self_ty = self.tcx.erase_regions(self_ty);
-
                 let impls_future = self.type_implements_trait(
                     future_trait,
-                    self_ty.skip_binder(),
+                    self.tcx.erase_late_bound_regions(self_ty),
                     ty::List::empty(),
                     obligation.param_env,
                 );
+                if !impls_future.must_apply_modulo_regions() {
+                    return;
+                }
 
                 let item_def_id = self.tcx.associated_item_def_ids(future_trait)[0];
                 // `<T as Future>::Output`
-                let projection_ty = ty::ProjectionTy {
-                    // `T`
-                    substs: self.tcx.mk_substs_trait(
-                        trait_pred.self_ty().skip_binder(),
-                        &self.fresh_substs_for_item(span, item_def_id)[1..],
-                    ),
-                    // `Future::Output`
-                    item_def_id,
-                };
-
-                let mut selcx = SelectionContext::new(self);
-
-                let mut obligations = vec![];
-                let normalized_ty = normalize_projection_type(
-                    &mut selcx,
+                let projection_ty = trait_pred.map_bound(|trait_pred| {
+                    self.tcx.mk_projection(
+                        item_def_id,
+                        // Future::Output has no substs
+                        self.tcx.mk_substs_trait(trait_pred.self_ty(), &[]),
+                    )
+                });
+                let projection_ty = normalize_to(
+                    &mut SelectionContext::new(self),
                     obligation.param_env,
-                    projection_ty,
                     obligation.cause.clone(),
-                    0,
-                    &mut obligations,
+                    projection_ty,
+                    &mut vec![],
                 );
 
                 debug!(
-                    "suggest_await_before_try: normalized_projection_type {:?}",
-                    self.resolve_vars_if_possible(normalized_ty)
+                    normalized_projection_type = ?self.resolve_vars_if_possible(projection_ty)
                 );
                 let try_obligation = self.mk_trait_obligation_with_new_self_ty(
                     obligation.param_env,
-                    trait_pred,
-                    normalized_ty.ty().unwrap(),
+                    trait_pred.map_bound(|trait_pred| (trait_pred, projection_ty.skip_binder())),
                 );
-                debug!("suggest_await_before_try: try_trait_obligation {:?}", try_obligation);
+                debug!(try_trait_obligation = ?try_obligation);
                 if self.predicate_may_hold(&try_obligation)
-                    && impls_future.must_apply_modulo_regions()
                     && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span)
                     && snippet.ends_with('?')
                 {
                     err.span_suggestion_verbose(
                         span.with_hi(span.hi() - BytePos(1)).shrink_to_hi(),
                         "consider `await`ing on the `Future`",
-                        ".await".to_string(),
+                        ".await",
                         Applicability::MaybeIncorrect,
                     );
                 }
@@ -2783,7 +2837,7 @@
                 err.span_suggestion_verbose(
                     rhs_span.shrink_to_hi(),
                     "consider using a floating-point literal by writing it with `.0`",
-                    String::from(".0"),
+                    ".0",
                     Applicability::MaybeIncorrect,
                 );
             }
@@ -2963,7 +3017,7 @@
         ret_ty,
         "use some type `T` that is `T: Sized` as the return type if all return paths have the \
             same type",
-        "T".to_string(),
+        "T",
         Applicability::MaybeIncorrect,
     );
     err.span_suggestion(
@@ -2990,3 +3044,52 @@
         );
     }
 }
+
+/// Collect the spans that we see the generic param `param_did`
+struct ReplaceImplTraitVisitor<'a> {
+    ty_spans: &'a mut Vec<Span>,
+    param_did: DefId,
+}
+
+impl<'a, 'hir> hir::intravisit::Visitor<'hir> for ReplaceImplTraitVisitor<'a> {
+    fn visit_ty(&mut self, t: &'hir hir::Ty<'hir>) {
+        if let hir::TyKind::Path(hir::QPath::Resolved(
+            None,
+            hir::Path { res: hir::def::Res::Def(_, segment_did), .. },
+        )) = t.kind
+        {
+            if self.param_did == *segment_did {
+                // `fn foo(t: impl Trait)`
+                //            ^^^^^^^^^^ get this to suggest `T` instead
+
+                // There might be more than one `impl Trait`.
+                self.ty_spans.push(t.span);
+                return;
+            }
+        }
+
+        hir::intravisit::walk_ty(self, t);
+    }
+}
+
+// Replace `param` with `replace_ty`
+struct ReplaceImplTraitFolder<'tcx> {
+    tcx: TyCtxt<'tcx>,
+    param: &'tcx ty::GenericParamDef,
+    replace_ty: Ty<'tcx>,
+}
+
+impl<'tcx> TypeFolder<'tcx> for ReplaceImplTraitFolder<'tcx> {
+    fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
+        if let ty::Param(ty::ParamTy { index, .. }) = t.kind() {
+            if self.param.index == *index {
+                return self.replace_ty;
+            }
+        }
+        t.super_fold_with(self)
+    }
+
+    fn tcx(&self) -> TyCtxt<'tcx> {
+        self.tcx
+    }
+}
diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs
index 053e871..d611664 100644
--- a/compiler/rustc_trait_selection/src/traits/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs
@@ -133,27 +133,16 @@
 
         let mut errors = Vec::new();
 
-        loop {
-            debug!("select: starting another iteration");
+        // Process pending obligations.
+        let outcome: Outcome<_, _> = self.predicates.process_obligations(&mut FulfillProcessor {
+            selcx,
+            register_region_obligations: self.register_region_obligations,
+        });
 
-            // Process pending obligations.
-            let outcome: Outcome<_, _> =
-                self.predicates.process_obligations(&mut FulfillProcessor {
-                    selcx,
-                    register_region_obligations: self.register_region_obligations,
-                });
-            debug!("select: outcome={:#?}", outcome);
+        // FIXME: if we kept the original cache key, we could mark projection
+        // obligations as complete for the projection cache here.
 
-            // FIXME: if we kept the original cache key, we could mark projection
-            // obligations as complete for the projection cache here.
-
-            errors.extend(outcome.errors.into_iter().map(to_fulfillment_error));
-
-            // If nothing new was added, no need to keep looping.
-            if outcome.stalled {
-                break;
-            }
-        }
+        errors.extend(outcome.errors.into_iter().map(to_fulfillment_error));
 
         debug!(
             "select({} predicates remaining, {} errors) done",
@@ -264,22 +253,16 @@
     type Obligation = PendingPredicateObligation<'tcx>;
     type Error = FulfillmentErrorCode<'tcx>;
 
-    /// Processes a predicate obligation and returns either:
-    /// - `Changed(v)` if the predicate is true, presuming that `v` are also true
-    /// - `Unchanged` if we don't have enough info to be sure
-    /// - `Error(e)` if the predicate does not hold
+    /// Identifies whether a predicate obligation needs processing.
     ///
     /// This is always inlined, despite its size, because it has a single
     /// callsite and it is called *very* frequently.
     #[inline(always)]
-    fn process_obligation(
-        &mut self,
-        pending_obligation: &mut Self::Obligation,
-    ) -> ProcessResult<Self::Obligation, Self::Error> {
+    fn needs_process_obligation(&self, pending_obligation: &Self::Obligation) -> bool {
         // If we were stalled on some unresolved variables, first check whether
         // any of them have been resolved; if not, don't bother doing more work
         // yet.
-        let change = match pending_obligation.stalled_on.len() {
+        match pending_obligation.stalled_on.len() {
             // Match arms are in order of frequency, which matters because this
             // code is so hot. 1 and 0 dominate; 2+ is fairly rare.
             1 => {
@@ -302,42 +285,18 @@
                     false
                 })()
             }
-        };
-
-        if !change {
-            debug!(
-                "process_predicate: pending obligation {:?} still stalled on {:?}",
-                self.selcx.infcx().resolve_vars_if_possible(pending_obligation.obligation.clone()),
-                pending_obligation.stalled_on
-            );
-            return ProcessResult::Unchanged;
-        }
-
-        self.process_changed_obligations(pending_obligation)
-    }
-
-    fn process_backedge<'c, I>(
-        &mut self,
-        cycle: I,
-        _marker: PhantomData<&'c PendingPredicateObligation<'tcx>>,
-    ) where
-        I: Clone + Iterator<Item = &'c PendingPredicateObligation<'tcx>>,
-    {
-        if self.selcx.coinductive_match(cycle.clone().map(|s| s.obligation.predicate)) {
-            debug!("process_child_obligations: coinductive match");
-        } else {
-            let cycle: Vec<_> = cycle.map(|c| c.obligation.clone()).collect();
-            self.selcx.infcx().report_overflow_error_cycle(&cycle);
         }
     }
-}
 
-impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
-    // The code calling this method is extremely hot and only rarely
-    // actually uses this, so move this part of the code
-    // out of that loop.
+    /// Processes a predicate obligation and returns either:
+    /// - `Changed(v)` if the predicate is true, presuming that `v` are also true
+    /// - `Unchanged` if we don't have enough info to be sure
+    /// - `Error(e)` if the predicate does not hold
+    ///
+    /// This is called much less often than `needs_process_obligation`, so we
+    /// never inline it.
     #[inline(never)]
-    fn process_changed_obligations(
+    fn process_obligation(
         &mut self,
         pending_obligation: &mut PendingPredicateObligation<'tcx>,
     ) -> ProcessResult<PendingPredicateObligation<'tcx>, FulfillmentErrorCode<'tcx>> {
@@ -352,6 +311,8 @@
                 self.selcx.infcx().resolve_vars_if_possible(obligation.predicate);
         }
 
+        let obligation = &pending_obligation.obligation;
+
         debug!(?obligation, ?obligation.cause, "process_obligation");
 
         let infcx = self.selcx.infcx();
@@ -578,7 +539,7 @@
                         //
                         // Let's just see where this breaks :shrug:
                         if let (ty::ConstKind::Unevaluated(a), ty::ConstKind::Unevaluated(b)) =
-                            (c1.val(), c2.val())
+                            (c1.kind(), c2.kind())
                         {
                             if infcx.try_unify_abstract_consts(
                                 a.shrink(),
@@ -593,23 +554,25 @@
                     let stalled_on = &mut pending_obligation.stalled_on;
 
                     let mut evaluate = |c: Const<'tcx>| {
-                        if let ty::ConstKind::Unevaluated(unevaluated) = c.val() {
-                            match self.selcx.infcx().const_eval_resolve(
+                        if let ty::ConstKind::Unevaluated(unevaluated) = c.kind() {
+                            match self.selcx.infcx().try_const_eval_resolve(
                                 obligation.param_env,
                                 unevaluated,
+                                c.ty(),
                                 Some(obligation.cause.span),
                             ) {
-                                Ok(val) => Ok(Const::from_value(self.selcx.tcx(), val, c.ty())),
-                                Err(ErrorHandled::TooGeneric) => {
-                                    stalled_on.extend(
-                                        unevaluated
-                                            .substs
-                                            .iter()
-                                            .filter_map(TyOrConstInferVar::maybe_from_generic_arg),
-                                    );
-                                    Err(ErrorHandled::TooGeneric)
-                                }
-                                Err(err) => Err(err),
+                                Ok(val) => Ok(val),
+                                Err(e) => match e {
+                                    ErrorHandled::TooGeneric => {
+                                        stalled_on.extend(
+                                            unevaluated.substs.iter().filter_map(
+                                                TyOrConstInferVar::maybe_from_generic_arg,
+                                            ),
+                                        );
+                                        Err(ErrorHandled::TooGeneric)
+                                    }
+                                    _ => Err(e),
+                                },
                             }
                         } else {
                             Ok(c)
@@ -666,6 +629,23 @@
         }
     }
 
+    fn process_backedge<'c, I>(
+        &mut self,
+        cycle: I,
+        _marker: PhantomData<&'c PendingPredicateObligation<'tcx>>,
+    ) where
+        I: Clone + Iterator<Item = &'c PendingPredicateObligation<'tcx>>,
+    {
+        if self.selcx.coinductive_match(cycle.clone().map(|s| s.obligation.predicate)) {
+            debug!("process_child_obligations: coinductive match");
+        } else {
+            let cycle: Vec<_> = cycle.map(|c| c.obligation.clone()).collect();
+            self.selcx.infcx().report_overflow_error_cycle(&cycle);
+        }
+    }
+}
+
+impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
     #[instrument(level = "debug", skip(self, obligation, stalled_on))]
     fn process_trait_obligation(
         &mut self,
diff --git a/compiler/rustc_trait_selection/src/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs
index b83b0bf..f04f527 100644
--- a/compiler/rustc_trait_selection/src/traits/misc.rs
+++ b/compiler/rustc_trait_selection/src/traits/misc.rs
@@ -20,7 +20,7 @@
     tcx: TyCtxt<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
     self_type: Ty<'tcx>,
-    cause: ObligationCause<'tcx>,
+    parent_cause: ObligationCause<'tcx>,
 ) -> Result<(), CopyImplementationError<'tcx>> {
     // FIXME: (@jroesch) float this code up
     tcx.infer_ctxt().enter(|infcx| {
@@ -59,7 +59,7 @@
                     .ty(tcx, traits::InternalSubsts::identity_for_item(tcx, adt.did()))
                     .has_param_types_or_consts()
                 {
-                    cause.clone()
+                    parent_cause.clone()
                 } else {
                     ObligationCause::dummy_with_span(span)
                 };
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index 8181953..34b0f43 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -23,7 +23,7 @@
 pub mod wf;
 
 use crate::infer::outlives::env::OutlivesEnvironment;
-use crate::infer::{InferCtxt, RegionckMode, TyCtxtInferExt};
+use crate::infer::{InferCtxt, TyCtxtInferExt};
 use crate::traits::error_reporting::InferCtxtExt as _;
 use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
 use rustc_errors::ErrorGuaranteed;
@@ -32,9 +32,7 @@
 use rustc_hir::lang_items::LangItem;
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::subst::{InternalSubsts, SubstsRef};
-use rustc_middle::ty::{
-    self, GenericParamDefKind, ToPredicate, Ty, TyCtxt, VtblEntry, COMMON_VTABLE_ENTRIES,
-};
+use rustc_middle::ty::{self, GenericParamDefKind, ToPredicate, Ty, TyCtxt, VtblEntry};
 use rustc_span::{sym, Span};
 use smallvec::SmallVec;
 
@@ -62,7 +60,7 @@
 pub use self::specialize::specialization_graph::FutureCompatOverlapErrorKind;
 pub use self::specialize::{specialization_graph, translate_substs, OverlapError};
 pub use self::structural_match::search_for_structural_match_violation;
-pub use self::structural_match::NonStructuralMatchTy;
+pub use self::structural_match::{NonStructuralMatchTy, NonStructuralMatchTyKind};
 pub use self::util::{
     elaborate_obligations, elaborate_predicates, elaborate_predicates_with_span,
     elaborate_trait_ref, elaborate_trait_refs,
@@ -242,11 +240,7 @@
         // cares about declarations like `'a: 'b`.
         let outlives_env = OutlivesEnvironment::new(elaborated_env);
 
-        infcx.resolve_regions_and_report_errors(
-            region_context,
-            &outlives_env,
-            RegionckMode::default(),
-        );
+        infcx.resolve_regions_and_report_errors(region_context, &outlives_env);
 
         let predicates = match infcx.fully_resolve(predicates) {
             Ok(predicates) => predicates,
@@ -695,7 +689,7 @@
     let vtable_segment_callback = |segment| -> ControlFlow<()> {
         match segment {
             VtblSegment::MetadataDSA => {
-                entries.extend(COMMON_VTABLE_ENTRIES);
+                entries.extend(TyCtxt::COMMON_VTABLE_ENTRIES);
             }
             VtblSegment::TraitOwnEntries { trait_ref, emit_vptr } => {
                 let existential_trait_ref = trait_ref
@@ -785,7 +779,7 @@
         move |segment| {
             match segment {
                 VtblSegment::MetadataDSA => {
-                    vtable_base += COMMON_VTABLE_ENTRIES.len();
+                    vtable_base += TyCtxt::COMMON_VTABLE_ENTRIES.len();
                 }
                 VtblSegment::TraitOwnEntries { trait_ref, emit_vptr } => {
                     if tcx.erase_regions(trait_ref) == trait_to_be_found_erased {
diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs
index e3e3847..132c335 100644
--- a/compiler/rustc_trait_selection/src/traits/object_safety.rs
+++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs
@@ -18,7 +18,9 @@
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_middle::ty::subst::{GenericArg, InternalSubsts, Subst};
-use rustc_middle::ty::{self, EarlyBinder, Ty, TyCtxt, TypeFoldable, TypeVisitor};
+use rustc_middle::ty::{
+    self, EarlyBinder, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable, TypeVisitor,
+};
 use rustc_middle::ty::{Predicate, ToPredicate};
 use rustc_session::lint::builtin::WHERE_CLAUSES_OBJECT_SAFETY;
 use rustc_span::symbol::Symbol;
@@ -98,7 +100,7 @@
                 span,
             ) = violation
             {
-                lint_object_unsafe_trait(tcx, *span, trait_def_id, violation);
+                lint_object_unsafe_trait(tcx, *span, trait_def_id, &violation);
                 false
             } else {
                 true
@@ -278,7 +280,7 @@
     (predicate, sp): (ty::Predicate<'tcx>, Span),
 ) -> Option<Span> {
     let self_ty = tcx.types.self_param;
-    let has_self_ty = |arg: &GenericArg<'_>| arg.walk().any(|arg| arg == self_ty.into());
+    let has_self_ty = |arg: &GenericArg<'tcx>| arg.walk().any(|arg| arg == self_ty.into());
     match predicate.kind().skip_binder() {
         ty::PredicateKind::Trait(ref data) => {
             // In the case of a trait predicate, we can skip the "self" type.
@@ -814,10 +816,7 @@
             }
         }
 
-        fn visit_unevaluated_const(
-            &mut self,
-            uv: ty::Unevaluated<'tcx>,
-        ) -> ControlFlow<Self::BreakTy> {
+        fn visit_unevaluated(&mut self, uv: ty::Unevaluated<'tcx>) -> ControlFlow<Self::BreakTy> {
             // Constants can only influence object safety if they reference `Self`.
             // This is only possible for unevaluated constants, so we walk these here.
             //
diff --git a/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs
index 7d41819..ed7d16f 100644
--- a/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs
+++ b/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs
@@ -89,8 +89,8 @@
                         None,
                     )
                 })?;
-            attr::eval_condition(cond, &tcx.sess.parse_sess, Some(tcx.features()), &mut |item| {
-                if let Some(symbol) = item.value_str() && let Err(guar) = parse_value(symbol) {
+            attr::eval_condition(cond, &tcx.sess.parse_sess, Some(tcx.features()), &mut |cfg| {
+                if let Some(value) = cfg.value && let Err(guar) = parse_value(value) {
                     errored = Some(guar);
                 }
                 true
@@ -226,14 +226,12 @@
                 condition,
                 &tcx.sess.parse_sess,
                 Some(tcx.features()),
-                &mut |c| {
-                    c.ident().map_or(false, |ident| {
-                        let value = c.value_str().map(|s| {
-                            OnUnimplementedFormatString(s).format(tcx, trait_ref, &options_map)
-                        });
+                &mut |cfg| {
+                    let value = cfg.value.map(|v| {
+                        OnUnimplementedFormatString(v).format(tcx, trait_ref, &options_map)
+                    });
 
-                        options.contains(&(ident.name, value))
-                    })
+                    options.contains(&(cfg.name, value))
                 },
             ) {
                 debug!("evaluate: skipping {:?} due to condition", command);
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index beaa56e..82c5429 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -28,8 +28,9 @@
 use rustc_hir::def_id::DefId;
 use rustc_hir::lang_items::LangItem;
 use rustc_infer::infer::resolve::OpportunisticRegionResolver;
+use rustc_infer::traits::ObligationCauseCode;
 use rustc_middle::traits::select::OverflowError;
-use rustc_middle::ty::fold::{MaxUniverse, TypeFoldable, TypeFolder};
+use rustc_middle::ty::fold::{MaxUniverse, TypeFoldable, TypeFolder, TypeSuperFoldable};
 use rustc_middle::ty::subst::Subst;
 use rustc_middle::ty::{self, EarlyBinder, Term, ToPredicate, Ty, TyCtxt};
 use rustc_span::symbol::sym;
@@ -145,15 +146,28 @@
     }
 }
 
-/// Takes the place of a
+/// States returned from `poly_project_and_unify_type`. Takes the place
+/// of the old return type, which was:
+/// ```ignore (not-rust)
 /// Result<
 ///     Result<Option<Vec<PredicateObligation<'tcx>>>, InProgress>,
 ///     MismatchedProjectionTypes<'tcx>,
 /// >
+/// ```
 pub(super) enum ProjectAndUnifyResult<'tcx> {
+    /// The projection bound holds subject to the given obligations. If the
+    /// projection cannot be normalized because the required trait bound does
+    /// not hold, this is returned, with `obligations` being a predicate that
+    /// cannot be proven.
     Holds(Vec<PredicateObligation<'tcx>>),
+    /// The projection cannot be normalized due to ambiguity. Resolving some
+    /// inference variables in the projection may fix this.
     FailedNormalization,
+    /// The project cannot be normalized because `poly_project_and_unify_type`
+    /// is called recursively while normalizing the same projection.
     Recursive,
+    // the projection can be normalized, but is not equal to the expected type.
+    // Returns the type error that arose from the mismatch.
     MismatchedProjectionTypes(MismatchedProjectionTypes<'tcx>),
 }
 
@@ -163,19 +177,6 @@
 /// ```
 /// If successful, this may result in additional obligations. Also returns
 /// the projection cache key used to track these additional obligations.
-///
-/// ## Returns
-///
-/// - `Err(_)`: the projection can be normalized, but is not equal to the
-///   expected type.
-/// - `Ok(Err(InProgress))`: this is called recursively while normalizing
-///   the same projection.
-/// - `Ok(Ok(None))`: The projection cannot be normalized due to ambiguity
-///   (resolving some inference variables in the projection may fix this).
-/// - `Ok(Ok(Some(obligations)))`: The projection bound holds subject to
-///    the given obligations. If the projection cannot be normalized because
-///    the required trait bound doesn't hold this returned with `obligations`
-///    being a predicate that cannot be proven.
 #[instrument(level = "debug", skip(selcx))]
 pub(super) fn poly_project_and_unify_type<'cx, 'tcx>(
     selcx: &mut SelectionContext<'cx, 'tcx>,
@@ -261,6 +262,7 @@
             actual,
             obligation.cause.body_id,
             obligation.cause.span,
+            ObligationCauseCode::MiscObligation,
             obligation.param_env,
         );
     obligations.extend(new);
@@ -514,7 +516,7 @@
                             self.selcx.infcx().report_overflow_error(&obligation, true);
                         }
 
-                        let substs = substs.super_fold_with(self);
+                        let substs = substs.fold_with(self);
                         let generic_ty = self.tcx().bound_type_of(def_id);
                         let concrete_ty = generic_ty.subst(self.tcx(), substs);
                         self.depth += 1;
@@ -531,8 +533,7 @@
                 // placeholders (see branch below). *Also*, we know that we can
                 // register an obligation to *later* project, since we know
                 // there won't be bound vars there.
-
-                let data = data.super_fold_with(self);
+                let data = data.fold_with(self);
                 let normalized_ty = if self.eager_inference_replacement {
                     normalize_projection_type(
                         self.selcx,
@@ -581,7 +582,7 @@
                 let infcx = self.selcx.infcx();
                 let (data, mapped_regions, mapped_types, mapped_consts) =
                     BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, data);
-                let data = data.super_fold_with(self);
+                let data = data.fold_with(self);
                 let normalized_ty = opt_normalize_projection_type(
                     self.selcx,
                     self.param_env,
@@ -619,11 +620,14 @@
         }
     }
 
+    #[instrument(skip(self), level = "debug")]
     fn fold_const(&mut self, constant: ty::Const<'tcx>) -> ty::Const<'tcx> {
         if self.selcx.tcx().lazy_normalization() || !self.eager_inference_replacement {
             constant
         } else {
             let constant = constant.super_fold_with(self);
+            debug!(?constant);
+            debug!("self.param_env: {:?}", self.param_env);
             constant.eval(self.selcx.tcx(), self.param_env)
         }
     }
@@ -671,7 +675,7 @@
             universe_indices,
         };
 
-        let value = value.super_fold_with(&mut replacer);
+        let value = value.fold_with(&mut replacer);
 
         (value, replacer.mapped_regions, replacer.mapped_types, replacer.mapped_consts)
     }
@@ -743,7 +747,7 @@
     }
 
     fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
-        match ct.val() {
+        match ct.kind() {
             ty::ConstKind::Bound(debruijn, _)
                 if debruijn.as_usize() + 1
                     > self.current_index.as_usize() + self.universe_indices.len() =>
@@ -759,7 +763,7 @@
                 self.mapped_consts.insert(p, bound_const);
                 self.infcx
                     .tcx
-                    .mk_const(ty::ConstS { val: ty::ConstKind::Placeholder(p), ty: ct.ty() })
+                    .mk_const(ty::ConstS { kind: ty::ConstKind::Placeholder(p), ty: ct.ty() })
             }
             _ if ct.has_vars_bound_at_or_above(self.current_index) => ct.super_fold_with(self),
             _ => ct,
@@ -773,7 +777,7 @@
     mapped_regions: BTreeMap<ty::PlaceholderRegion, ty::BoundRegion>,
     mapped_types: BTreeMap<ty::PlaceholderType, ty::BoundTy>,
     mapped_consts: BTreeMap<ty::PlaceholderConst<'tcx>, ty::BoundVar>,
-    universe_indices: &'me Vec<Option<ty::UniverseIndex>>,
+    universe_indices: &'me [Option<ty::UniverseIndex>],
     current_index: ty::DebruijnIndex,
 }
 
@@ -783,7 +787,7 @@
         mapped_regions: BTreeMap<ty::PlaceholderRegion, ty::BoundRegion>,
         mapped_types: BTreeMap<ty::PlaceholderType, ty::BoundTy>,
         mapped_consts: BTreeMap<ty::PlaceholderConst<'tcx>, ty::BoundVar>,
-        universe_indices: &'me Vec<Option<ty::UniverseIndex>>,
+        universe_indices: &'me [Option<ty::UniverseIndex>],
         value: T,
     ) -> T {
         let mut replacer = PlaceholderReplacer {
@@ -794,7 +798,7 @@
             universe_indices,
             current_index: ty::INNERMOST,
         };
-        value.super_fold_with(&mut replacer)
+        value.fold_with(&mut replacer)
     }
 }
 
@@ -879,7 +883,7 @@
     }
 
     fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
-        if let ty::ConstKind::Placeholder(p) = ct.val() {
+        if let ty::ConstKind::Placeholder(p) = ct.kind() {
             let replace_var = self.mapped_consts.get(&p);
             match replace_var {
                 Some(replace_var) => {
@@ -892,7 +896,7 @@
                         self.universe_indices.len() - index + self.current_index.as_usize() - 1,
                     );
                     self.tcx().mk_const(ty::ConstS {
-                        val: ty::ConstKind::Bound(db, *replace_var),
+                        kind: ty::ConstKind::Bound(db, *replace_var),
                         ty: ct.ty(),
                     })
                 }
@@ -1921,7 +1925,7 @@
     let cause = &obligation.cause;
     let param_env = obligation.param_env;
 
-    let (cache_entry, _) = infcx.replace_bound_vars_with_fresh_vars(
+    let cache_entry = infcx.replace_bound_vars_with_fresh_vars(
         cause.span,
         LateBoundRegionConversionTime::HigherRankedType,
         poly_cache_entry,
@@ -2019,8 +2023,8 @@
         let identity_substs =
             crate::traits::InternalSubsts::identity_for_item(tcx, assoc_ty.item.def_id);
         let did = ty::WithOptConstParam::unknown(assoc_ty.item.def_id);
-        let val = ty::ConstKind::Unevaluated(ty::Unevaluated::new(did, identity_substs));
-        tcx.mk_const(ty::ConstS { ty, val }).into()
+        let kind = ty::ConstKind::Unevaluated(ty::Unevaluated::new(did, identity_substs));
+        tcx.mk_const(ty::ConstS { ty, kind }).into()
     } else {
         ty.into()
     };
@@ -2116,7 +2120,7 @@
     }
 }
 
-crate trait ProjectionCacheKeyExt<'cx, 'tcx>: Sized {
+pub(crate) trait ProjectionCacheKeyExt<'cx, 'tcx>: Sized {
     fn from_poly_projection_predicate(
         selcx: &mut SelectionContext<'cx, 'tcx>,
         predicate: ty::PolyProjectionPredicate<'tcx>,
diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
index 6a81a77..b80a27e 100644
--- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
@@ -12,7 +12,7 @@
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_infer::traits::Normalized;
 use rustc_middle::mir;
-use rustc_middle::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeFolder};
+use rustc_middle::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeFolder, TypeSuperFoldable};
 use rustc_middle::ty::subst::Subst;
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitor};
 
@@ -100,7 +100,7 @@
     }
 }
 
-/// Visitor to find the maximum escaping bound var
+// Visitor to find the maximum escaping bound var
 struct MaxEscapingBoundVarVisitor {
     // The index which would count as escaping
     outer_index: ty::DebruijnIndex,
@@ -141,7 +141,7 @@
     }
 
     fn visit_const(&mut self, ct: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
-        match ct.val() {
+        match ct.kind() {
             ty::ConstKind::Bound(debruijn, _) if debruijn >= self.outer_index => {
                 self.escaping =
                     self.escaping.max(debruijn.as_usize() - self.outer_index.as_usize());
@@ -205,7 +205,7 @@
                     Reveal::UserFacing => ty.try_super_fold_with(self),
 
                     Reveal::All => {
-                        let substs = substs.try_super_fold_with(self)?;
+                        let substs = substs.try_fold_with(self)?;
                         let recursion_limit = self.tcx().recursion_limit();
                         if !recursion_limit.value_within_limit(self.anon_depth) {
                             let obligation = Obligation::with_depth(
@@ -242,7 +242,7 @@
                 // we don't need to replace them with placeholders (see branch below).
 
                 let tcx = self.infcx.tcx;
-                let data = data.try_super_fold_with(self)?;
+                let data = data.try_fold_with(self)?;
 
                 let mut orig_values = OriginalQueryValues::default();
                 // HACK(matthewjasper) `'static` is special-cased in selection,
@@ -281,7 +281,7 @@
                         &mut self.universes,
                         data,
                     );
-                let data = data.try_super_fold_with(self)?;
+                let data = data.try_fold_with(self)?;
 
                 let mut orig_values = OriginalQueryValues::default();
                 // HACK(matthewjasper) `'static` is special-cased in selection,
@@ -334,21 +334,22 @@
         &mut self,
         constant: mir::ConstantKind<'tcx>,
     ) -> Result<mir::ConstantKind<'tcx>, Self::Error> {
-        let constant_kind = match constant {
+        Ok(match constant {
             mir::ConstantKind::Ty(c) => {
-                let const_folded = c.try_fold_with(self)?;
-                match const_folded.val() {
-                    ty::ConstKind::Value(cv) => {
-                        // FIXME With Valtrees we need to convert `cv: ValTree`
-                        // to a `ConstValue` here.
-                        mir::ConstantKind::Val(cv, const_folded.ty())
+                let const_folded = c.try_super_fold_with(self)?;
+                match const_folded.kind() {
+                    ty::ConstKind::Value(valtree) => {
+                        let tcx = self.infcx.tcx;
+                        let ty = const_folded.ty();
+                        let const_val = tcx.valtree_to_const_val((ty, valtree));
+                        debug!(?ty, ?valtree, ?const_val);
+
+                        mir::ConstantKind::Val(const_val, ty)
                     }
                     _ => mir::ConstantKind::Ty(const_folded),
                 }
             }
             mir::ConstantKind::Val(_, _) => constant.try_super_fold_with(self)?,
-        };
-
-        Ok(constant_kind)
+        })
     }
 }
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs
index 04c382d..46d6e97 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs
@@ -1,7 +1,7 @@
 use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse};
 use crate::traits::query::Fallible;
 use rustc_infer::traits::query::OutlivesBound;
-use rustc_middle::ty::{ParamEnvAnd, Ty, TyCtxt};
+use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt};
 
 #[derive(Copy, Clone, Debug, HashStable, TypeFoldable, Lift)]
 pub struct ImpliedOutlivesBounds<'tcx> {
@@ -13,9 +13,16 @@
 
     fn try_fast_path(
         _tcx: TyCtxt<'tcx>,
-        _key: &ParamEnvAnd<'tcx, Self>,
+        key: &ParamEnvAnd<'tcx, Self>,
     ) -> Option<Self::QueryResponse> {
-        None
+        // Don't go into the query for things that can't possibly have lifetimes.
+        match key.value.ty.kind() {
+            ty::Tuple(elems) if elems.is_empty() => Some(vec![]),
+            ty::Never | ty::Str | ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) => {
+                Some(vec![])
+            }
+            _ => None,
+        }
     }
 
     fn perform_query(
diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
index 07720ba..cfd50c1 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -539,8 +539,16 @@
             obligation.predicate.def_id(),
             obligation.predicate.skip_binder().trait_ref.self_ty(),
             |impl_def_id| {
+                // Before we create the substitutions and everything, first
+                // consider a "quick reject". This avoids creating more types
+                // and so forth that we need to.
+                let impl_trait_ref = self.tcx().bound_impl_trait_ref(impl_def_id).unwrap();
+                if self.fast_reject_trait_refs(obligation, &impl_trait_ref.0) {
+                    return;
+                }
+
                 self.infcx.probe(|_| {
-                    if let Ok(_substs) = self.match_impl(impl_def_id, obligation) {
+                    if let Ok(_substs) = self.match_impl(impl_def_id, impl_trait_ref, obligation) {
                         candidates.vec.push(ImplCandidate(impl_def_id));
                     }
                 });
@@ -962,7 +970,7 @@
 
                 if let Some(impl_def_id) = relevant_impl {
                     // Check that `impl Drop` is actually const, if there is a custom impl
-                    if self.tcx().impl_constness(impl_def_id) == hir::Constness::Const {
+                    if self.tcx().constness(impl_def_id) == hir::Constness::Const {
                         candidates.vec.push(ConstDestructCandidate(Some(impl_def_id)));
                     }
                 } else {
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index b9025c9..5942bb7 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -12,22 +12,20 @@
 use rustc_infer::infer::InferOk;
 use rustc_infer::infer::LateBoundRegionConversionTime::HigherRankedType;
 use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst, SubstsRef};
-use rustc_middle::ty::{self, EarlyBinder, GenericParamDefKind, Ty};
+use rustc_middle::ty::{self, EarlyBinder, GenericParamDefKind, Ty, TyCtxt};
 use rustc_middle::ty::{ToPolyTraitRef, ToPredicate};
 use rustc_span::def_id::DefId;
 
 use crate::traits::project::{normalize_with_depth, normalize_with_depth_to};
-use crate::traits::select::TraitObligationExt;
 use crate::traits::util::{self, closure_trait_ref_and_return_type, predicate_for_trait_def};
 use crate::traits::{
-    BuiltinDerivedObligation, DerivedObligationCause, ImplDerivedObligation,
-    ImplDerivedObligationCause, ImplSource, ImplSourceAutoImplData, ImplSourceBuiltinData,
-    ImplSourceClosureData, ImplSourceConstDestructData, ImplSourceDiscriminantKindData,
-    ImplSourceFnPointerData, ImplSourceGeneratorData, ImplSourceObjectData, ImplSourcePointeeData,
-    ImplSourceTraitAliasData, ImplSourceTraitUpcastingData, ImplSourceUserDefinedData, Normalized,
-    ObjectCastObligation, Obligation, ObligationCause, OutputTypeParameterMismatch,
-    PredicateObligation, Selection, SelectionError, TraitNotObjectSafe, TraitObligation,
-    Unimplemented, VtblSegment,
+    BuiltinDerivedObligation, ImplDerivedObligation, ImplDerivedObligationCause, ImplSource,
+    ImplSourceAutoImplData, ImplSourceBuiltinData, ImplSourceClosureData,
+    ImplSourceConstDestructData, ImplSourceDiscriminantKindData, ImplSourceFnPointerData,
+    ImplSourceGeneratorData, ImplSourceObjectData, ImplSourcePointeeData, ImplSourceTraitAliasData,
+    ImplSourceTraitUpcastingData, ImplSourceUserDefinedData, Normalized, ObjectCastObligation,
+    Obligation, ObligationCause, OutputTypeParameterMismatch, PredicateObligation, Selection,
+    SelectionError, TraitNotObjectSafe, TraitObligation, Unimplemented, VtblSegment,
 };
 
 use super::BuiltinImplConditions;
@@ -423,14 +421,11 @@
         let object_trait_ref = data.principal().unwrap_or_else(|| {
             span_bug!(obligation.cause.span, "object candidate with no principal")
         });
-        let object_trait_ref = self
-            .infcx
-            .replace_bound_vars_with_fresh_vars(
-                obligation.cause.span,
-                HigherRankedType,
-                object_trait_ref,
-            )
-            .0;
+        let object_trait_ref = self.infcx.replace_bound_vars_with_fresh_vars(
+            obligation.cause.span,
+            HigherRankedType,
+            object_trait_ref,
+        );
         let object_trait_ref = object_trait_ref.with_self_ty(self.tcx(), self_ty);
 
         let mut nested = vec![];
@@ -547,7 +542,7 @@
                                 bound_vars.push(bound_var);
                                 tcx.mk_const(ty::ConstS {
                                     ty: tcx.type_of(param.def_id),
-                                    val: ty::ConstKind::Bound(
+                                    kind: ty::ConstKind::Bound(
                                         ty::INNERMOST,
                                         ty::BoundVar::from_usize(bound_vars.len() - 1),
                                     ),
@@ -836,7 +831,7 @@
             move |segment| {
                 match segment {
                     VtblSegment::MetadataDSA => {
-                        vptr_offset += ty::COMMON_VTABLE_ENTRIES.len();
+                        vptr_offset += TyCtxt::COMMON_VTABLE_ENTRIES.len();
                     }
                     VtblSegment::TraitOwnEntries { trait_ref, emit_vptr } => {
                         vptr_offset += util::count_own_vtable_entries(tcx, trait_ref);
@@ -994,7 +989,7 @@
                     // Lifetimes aren't allowed to change during unsizing.
                     GenericArgKind::Lifetime(_) => None,
 
-                    GenericArgKind::Const(ct) => match ct.val() {
+                    GenericArgKind::Const(ct) => match ct.kind() {
                         ty::ConstKind::Param(p) => Some(p.index),
                         _ => None,
                     },
@@ -1128,21 +1123,13 @@
                 let substs = self.rematch_impl(impl_def_id, &new_obligation);
                 debug!(?substs, "impl substs");
 
-                let derived = DerivedObligationCause {
-                    parent_trait_pred: obligation.predicate,
-                    parent_code: obligation.cause.clone_code(),
-                };
-                let derived_code = ImplDerivedObligation(Box::new(ImplDerivedObligationCause {
-                    derived,
-                    impl_def_id,
-                    span: obligation.cause.span,
-                }));
-
-                let cause = ObligationCause::new(
-                    obligation.cause.span,
-                    obligation.cause.body_id,
-                    derived_code,
-                );
+                let cause = obligation.derived_cause(|derived| {
+                    ImplDerivedObligation(Box::new(ImplDerivedObligationCause {
+                        derived,
+                        impl_def_id,
+                        span: obligation.cause.span,
+                    }))
+                });
                 ensure_sufficient_stack(|| {
                     self.vtable_impl(
                         impl_def_id,
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 1c9f83f..2641faf 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -14,9 +14,9 @@
 use super::util::{closure_trait_ref_and_return_type, predicate_for_trait_def};
 use super::wf;
 use super::{
-    DerivedObligationCause, ErrorReporting, ImplDerivedObligation, ImplDerivedObligationCause,
-    Normalized, Obligation, ObligationCause, ObligationCauseCode, Overflow, PredicateObligation,
-    Selection, SelectionError, SelectionResult, TraitObligation, TraitQueryMode,
+    ErrorReporting, ImplDerivedObligation, ImplDerivedObligationCause, Normalized, Obligation,
+    ObligationCause, ObligationCauseCode, Overflow, PredicateObligation, Selection, SelectionError,
+    SelectionResult, TraitObligation, TraitQueryMode,
 };
 
 use crate::infer::{InferCtxt, InferOk, TypeFreshener};
@@ -33,11 +33,11 @@
 use rustc_middle::dep_graph::{DepKind, DepNodeIndex};
 use rustc_middle::mir::interpret::ErrorHandled;
 use rustc_middle::thir::abstract_const::NotConstEvaluatable;
-use rustc_middle::ty::fast_reject::{self, TreatParams};
+use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
 use rustc_middle::ty::fold::BottomUpFolder;
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::relate::TypeRelation;
-use rustc_middle::ty::subst::{GenericArgKind, Subst, SubstsRef};
+use rustc_middle::ty::subst::{Subst, SubstsRef};
 use rustc_middle::ty::{self, EarlyBinder, PolyProjectionPredicate, ToPolyTraitRef, ToPredicate};
 use rustc_middle::ty::{Ty, TyCtxt, TypeFoldable};
 use rustc_span::symbol::sym;
@@ -103,22 +103,31 @@
     /// require themselves.
     freshener: TypeFreshener<'cx, 'tcx>,
 
-    /// If `true`, indicates that the evaluation should be conservative
-    /// and consider the possibility of types outside this crate.
+    /// During coherence we have to assume that other crates may add
+    /// additional impls which we currently don't know about.
+    ///
+    /// To deal with this evaluation should be conservative
+    /// and consider the possibility of impls from outside this crate.
     /// This comes up primarily when resolving ambiguity. Imagine
     /// there is some trait reference `$0: Bar` where `$0` is an
     /// inference variable. If `intercrate` is true, then we can never
     /// say for sure that this reference is not implemented, even if
     /// there are *no impls at all for `Bar`*, because `$0` could be
     /// bound to some type that in a downstream crate that implements
-    /// `Bar`. This is the suitable mode for coherence. Elsewhere,
-    /// though, we set this to false, because we are only interested
-    /// in types that the user could actually have written --- in
-    /// other words, we consider `$0: Bar` to be unimplemented if
+    /// `Bar`.
+    ///
+    /// Outside of coherence we set this to false because we are only
+    /// interested in types that the user could actually have written.
+    /// In other words, we consider `$0: Bar` to be unimplemented if
     /// there is no type that the user could *actually name* that
     /// would satisfy it. This avoids crippling inference, basically.
     intercrate: bool,
-
+    /// If `intercrate` is set, we remember predicates which were
+    /// considered ambiguous because of impls potentially added in other crates.
+    /// This is used in coherence to give improved diagnostics.
+    /// We don't do his until we detect a coherence error because it can
+    /// lead to false overflow results (#47139) and because always
+    /// computing it may negatively impact performance.
     intercrate_ambiguity_causes: Option<Vec<IntercrateAmbiguityCause>>,
 
     /// The mode that trait queries run in, which informs our error handling
@@ -240,11 +249,8 @@
         }
     }
 
-    /// Enables tracking of intercrate ambiguity causes. These are
-    /// used in coherence to give improved diagnostics. We don't do
-    /// this until we detect a coherence error because it can lead to
-    /// false overflow results (#47139) and because it costs
-    /// computation time.
+    /// Enables tracking of intercrate ambiguity causes. See
+    /// the documentation of [`Self::intercrate_ambiguity_causes`] for more.
     pub fn enable_tracking_intercrate_ambiguity_causes(&mut self) {
         assert!(self.intercrate);
         assert!(self.intercrate_ambiguity_causes.is_none());
@@ -326,7 +332,7 @@
         }
     }
 
-    crate fn select_from_obligation(
+    pub(crate) fn select_from_obligation(
         &mut self,
         obligation: &TraitObligation<'tcx>,
     ) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> {
@@ -388,6 +394,10 @@
                 Err(_) => return Ok(EvaluatedToErr),
             }
 
+            if self.infcx.opaque_types_added_in_snapshot(snapshot) {
+                return Ok(result.max(EvaluatedToOkModuloOpaqueTypes));
+            }
+
             match self.infcx.region_constraints_added_in_snapshot(snapshot) {
                 None => Ok(result),
                 Some(_) => Ok(result.max(EvaluatedToOkModuloRegions)),
@@ -616,7 +626,7 @@
                         //
                         // Let's just see where this breaks :shrug:
                         if let (ty::ConstKind::Unevaluated(a), ty::ConstKind::Unevaluated(b)) =
-                            (c1.val(), c2.val())
+                            (c1.kind(), c2.kind())
                         {
                             if self.infcx.try_unify_abstract_consts(
                                 a.shrink(),
@@ -629,14 +639,16 @@
                     }
 
                     let evaluate = |c: ty::Const<'tcx>| {
-                        if let ty::ConstKind::Unevaluated(unevaluated) = c.val() {
-                            self.infcx
-                                .const_eval_resolve(
-                                    obligation.param_env,
-                                    unevaluated,
-                                    Some(obligation.cause.span),
-                                )
-                                .map(|val| ty::Const::from_value(self.tcx(), val, c.ty()))
+                        if let ty::ConstKind::Unevaluated(unevaluated) = c.kind() {
+                            match self.infcx.try_const_eval_resolve(
+                                obligation.param_env,
+                                unevaluated,
+                                c.ty(),
+                                Some(obligation.cause.span),
+                            ) {
+                                Ok(val) => Ok(val),
+                                Err(e) => Err(e),
+                            }
                         } else {
                             Ok(c)
                         }
@@ -1111,8 +1123,7 @@
             if obligation.is_const() {
                 match candidate {
                     // const impl
-                    ImplCandidate(def_id)
-                        if tcx.impl_constness(def_id) == hir::Constness::Const => {}
+                    ImplCandidate(def_id) if tcx.constness(def_id) == hir::Constness::Const => {}
                     // const param
                     ParamCandidate(trait_pred) if trait_pred.is_const_if_const() => {}
                     // auto trait impl
@@ -1447,7 +1458,7 @@
         potentially_unnormalized_candidates: bool,
     ) -> ProjectionMatchesProjection {
         let mut nested_obligations = Vec::new();
-        let (infer_predicate, _) = self.infcx.replace_bound_vars_with_fresh_vars(
+        let infer_predicate = self.infcx.replace_bound_vars_with_fresh_vars(
             obligation.cause.span,
             LateBoundRegionConversionTime::HigherRankedType,
             env_predicate,
@@ -2037,7 +2048,8 @@
         impl_def_id: DefId,
         obligation: &TraitObligation<'tcx>,
     ) -> Normalized<'tcx, SubstsRef<'tcx>> {
-        match self.match_impl(impl_def_id, obligation) {
+        let impl_trait_ref = self.tcx().bound_impl_trait_ref(impl_def_id).unwrap();
+        match self.match_impl(impl_def_id, impl_trait_ref, obligation) {
             Ok(substs) => substs,
             Err(()) => {
                 self.infcx.tcx.sess.delay_span_bug(
@@ -2064,17 +2076,9 @@
     fn match_impl(
         &mut self,
         impl_def_id: DefId,
+        impl_trait_ref: EarlyBinder<ty::TraitRef<'tcx>>,
         obligation: &TraitObligation<'tcx>,
     ) -> Result<Normalized<'tcx, SubstsRef<'tcx>>, ()> {
-        let impl_trait_ref = self.tcx().bound_impl_trait_ref(impl_def_id).unwrap();
-
-        // Before we create the substitutions and everything, first
-        // consider a "quick reject". This avoids creating more types
-        // and so forth that we need to.
-        if self.fast_reject_trait_refs(obligation, &impl_trait_ref.0) {
-            return Err(());
-        }
-
         let placeholder_obligation =
             self.infcx().replace_bound_vars_with_placeholders(obligation.predicate);
         let placeholder_obligation_trait_ref = placeholder_obligation.trait_ref;
@@ -2131,43 +2135,9 @@
         // We can avoid creating type variables and doing the full
         // substitution if we find that any of the input types, when
         // simplified, do not match.
-
-        iter::zip(obligation.predicate.skip_binder().trait_ref.substs, impl_trait_ref.substs).any(
-            |(obligation_arg, impl_arg)| {
-                match (obligation_arg.unpack(), impl_arg.unpack()) {
-                    (GenericArgKind::Type(obligation_ty), GenericArgKind::Type(impl_ty)) => {
-                        // Note, we simplify parameters for the obligation but not the
-                        // impl so that we do not reject a blanket impl but do reject
-                        // more concrete impls if we're searching for `T: Trait`.
-                        let simplified_obligation_ty = fast_reject::simplify_type(
-                            self.tcx(),
-                            obligation_ty,
-                            TreatParams::AsBoundTypes,
-                        );
-                        let simplified_impl_ty = fast_reject::simplify_type(
-                            self.tcx(),
-                            impl_ty,
-                            TreatParams::AsPlaceholders,
-                        );
-
-                        simplified_obligation_ty.is_some()
-                            && simplified_impl_ty.is_some()
-                            && simplified_obligation_ty != simplified_impl_ty
-                    }
-                    (GenericArgKind::Lifetime(_), GenericArgKind::Lifetime(_)) => {
-                        // Lifetimes can never cause a rejection.
-                        false
-                    }
-                    (GenericArgKind::Const(_), GenericArgKind::Const(_)) => {
-                        // Conservatively ignore consts (i.e. assume they might
-                        // unify later) until we have `fast_reject` support for
-                        // them (if we'll ever need it, even).
-                        false
-                    }
-                    _ => unreachable!(),
-                }
-            },
-        )
+        let drcx = DeepRejectCtxt { treat_obligation_params: TreatParams::AsPlaceholder };
+        iter::zip(obligation.predicate.skip_binder().trait_ref.substs, impl_trait_ref.substs)
+            .any(|(obl, imp)| !drcx.generic_args_may_unify(obl, imp))
     }
 
     /// Normalize `where_clause_trait_ref` and try to match it against
@@ -2314,17 +2284,15 @@
         debug!(?predicates);
         assert_eq!(predicates.parent, None);
         let mut obligations = Vec::with_capacity(predicates.predicates.len());
-        let parent_code = cause.clone_code();
         for (predicate, span) in predicates.predicates {
             let span = *span;
-            let derived =
-                DerivedObligationCause { parent_trait_pred, parent_code: parent_code.clone() };
-            let code = ImplDerivedObligation(Box::new(ImplDerivedObligationCause {
-                derived,
-                impl_def_id: def_id,
-                span,
-            }));
-            let cause = ObligationCause::new(cause.span, cause.body_id, code);
+            let cause = cause.clone().derived_cause(parent_trait_pred, |derived| {
+                ImplDerivedObligation(Box::new(ImplDerivedObligationCause {
+                    derived,
+                    impl_def_id: def_id,
+                    span,
+                }))
+            });
             let predicate = normalize_with_depth_to(
                 self,
                 param_env,
@@ -2340,42 +2308,6 @@
     }
 }
 
-trait TraitObligationExt<'tcx> {
-    fn derived_cause(
-        &self,
-        variant: fn(DerivedObligationCause<'tcx>) -> ObligationCauseCode<'tcx>,
-    ) -> ObligationCause<'tcx>;
-}
-
-impl<'tcx> TraitObligationExt<'tcx> for TraitObligation<'tcx> {
-    fn derived_cause(
-        &self,
-        variant: fn(DerivedObligationCause<'tcx>) -> ObligationCauseCode<'tcx>,
-    ) -> ObligationCause<'tcx> {
-        /*!
-         * Creates a cause for obligations that are derived from
-         * `obligation` by a recursive search (e.g., for a builtin
-         * bound, or eventually a `auto trait Foo`). If `obligation`
-         * is itself a derived obligation, this is just a clone, but
-         * otherwise we create a "derived obligation" cause so as to
-         * keep track of the original root obligation for error
-         * reporting.
-         */
-
-        let obligation = self;
-
-        // NOTE(flaper87): As of now, it keeps track of the whole error
-        // chain. Ideally, we should have a way to configure this either
-        // by using -Z verbose or just a CLI argument.
-        let derived_cause = DerivedObligationCause {
-            parent_trait_pred: obligation.predicate,
-            parent_code: obligation.cause.clone_code(),
-        };
-        let derived_code = variant(derived_cause);
-        ObligationCause::new(obligation.cause.span, obligation.cause.body_id, derived_code)
-    }
-}
-
 impl<'o, 'tcx> TraitObligationStack<'o, 'tcx> {
     fn list(&'o self) -> TraitObligationStackList<'o, 'tcx> {
         TraitObligationStackList::with(self)
diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
index bca1d15..95f1e22 100644
--- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
@@ -486,7 +486,7 @@
 
 /// Recovers the "impl X for Y" signature from `impl_def_id` and returns it as a
 /// string.
-crate fn to_pretty_impl_header(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Option<String> {
+pub(crate) fn to_pretty_impl_header(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Option<String> {
     use std::fmt::Write;
 
     let trait_ref = tcx.impl_trait_ref(impl_def_id)?;
diff --git a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
index 8b23dcf..930c80e 100644
--- a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
+++ b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
@@ -49,8 +49,7 @@
     /// Insert an impl into this set of children without comparing to any existing impls.
     fn insert_blindly(&mut self, tcx: TyCtxt<'_>, impl_def_id: DefId) {
         let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
-        if let Some(st) =
-            fast_reject::simplify_type(tcx, trait_ref.self_ty(), TreatParams::AsPlaceholders)
+        if let Some(st) = fast_reject::simplify_type(tcx, trait_ref.self_ty(), TreatParams::AsInfer)
         {
             debug!("insert_blindly: impl_def_id={:?} st={:?}", impl_def_id, st);
             self.non_blanket_impls.entry(st).or_default().push(impl_def_id)
@@ -66,8 +65,7 @@
     fn remove_existing(&mut self, tcx: TyCtxt<'_>, impl_def_id: DefId) {
         let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
         let vec: &mut Vec<DefId>;
-        if let Some(st) =
-            fast_reject::simplify_type(tcx, trait_ref.self_ty(), TreatParams::AsPlaceholders)
+        if let Some(st) = fast_reject::simplify_type(tcx, trait_ref.self_ty(), TreatParams::AsInfer)
         {
             debug!("remove_existing: impl_def_id={:?} st={:?}", impl_def_id, st);
             vec = self.non_blanket_impls.get_mut(&st).unwrap();
@@ -316,8 +314,7 @@
 
         let mut parent = trait_def_id;
         let mut last_lint = None;
-        let simplified =
-            fast_reject::simplify_type(tcx, trait_ref.self_ty(), TreatParams::AsPlaceholders);
+        let simplified = fast_reject::simplify_type(tcx, trait_ref.self_ty(), TreatParams::AsInfer);
 
         // Descend the specialization tree, where `parent` is the current parent node.
         loop {
diff --git a/compiler/rustc_trait_selection/src/traits/structural_match.rs b/compiler/rustc_trait_selection/src/traits/structural_match.rs
index 67e3bf8..bc2ce31 100644
--- a/compiler/rustc_trait_selection/src/traits/structural_match.rs
+++ b/compiler/rustc_trait_selection/src/traits/structural_match.rs
@@ -6,12 +6,18 @@
 use rustc_hir as hir;
 use rustc_hir::lang_items::LangItem;
 use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt, TypeFoldable, TypeVisitor};
+use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable, TypeVisitor};
 use rustc_span::Span;
 use std::ops::ControlFlow;
 
 #[derive(Debug)]
-pub enum NonStructuralMatchTy<'tcx> {
+pub struct NonStructuralMatchTy<'tcx> {
+    pub ty: Ty<'tcx>,
+    pub kind: NonStructuralMatchTyKind<'tcx>,
+}
+
+#[derive(Debug)]
+pub enum NonStructuralMatchTyKind<'tcx> {
     Adt(AdtDef<'tcx>),
     Param,
     Dynamic,
@@ -137,25 +143,32 @@
         let (adt_def, substs) = match *ty.kind() {
             ty::Adt(adt_def, substs) => (adt_def, substs),
             ty::Param(_) => {
-                return ControlFlow::Break(NonStructuralMatchTy::Param);
+                let kind = NonStructuralMatchTyKind::Param;
+                return ControlFlow::Break(NonStructuralMatchTy { ty, kind });
             }
             ty::Dynamic(..) => {
-                return ControlFlow::Break(NonStructuralMatchTy::Dynamic);
+                let kind = NonStructuralMatchTyKind::Dynamic;
+                return ControlFlow::Break(NonStructuralMatchTy { ty, kind });
             }
             ty::Foreign(_) => {
-                return ControlFlow::Break(NonStructuralMatchTy::Foreign);
+                let kind = NonStructuralMatchTyKind::Foreign;
+                return ControlFlow::Break(NonStructuralMatchTy { ty, kind });
             }
             ty::Opaque(..) => {
-                return ControlFlow::Break(NonStructuralMatchTy::Opaque);
+                let kind = NonStructuralMatchTyKind::Opaque;
+                return ControlFlow::Break(NonStructuralMatchTy { ty, kind });
             }
             ty::Projection(..) => {
-                return ControlFlow::Break(NonStructuralMatchTy::Projection);
+                let kind = NonStructuralMatchTyKind::Projection;
+                return ControlFlow::Break(NonStructuralMatchTy { ty, kind });
             }
             ty::Closure(..) => {
-                return ControlFlow::Break(NonStructuralMatchTy::Closure);
+                let kind = NonStructuralMatchTyKind::Closure;
+                return ControlFlow::Break(NonStructuralMatchTy { ty, kind });
             }
             ty::Generator(..) | ty::GeneratorWitness(..) => {
-                return ControlFlow::Break(NonStructuralMatchTy::Generator);
+                let kind = NonStructuralMatchTyKind::Generator;
+                return ControlFlow::Break(NonStructuralMatchTy { ty, kind });
             }
             ty::RawPtr(..) => {
                 // structural-match ignores substructure of
@@ -215,7 +228,8 @@
 
         if !self.type_marked_structural(ty) {
             debug!("Search found ty: {:?}", ty);
-            return ControlFlow::Break(NonStructuralMatchTy::Adt(adt_def));
+            let kind = NonStructuralMatchTyKind::Adt(adt_def);
+            return ControlFlow::Break(NonStructuralMatchTy { ty, kind });
         }
 
         // structural-match does not care about the
diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs
index f2e31c0..3a00c41 100644
--- a/compiler/rustc_trait_selection/src/traits/util.rs
+++ b/compiler/rustc_trait_selection/src/traits/util.rs
@@ -304,22 +304,24 @@
     tcx: TyCtxt<'tcx>,
     object: &super::ImplSourceObjectData<'tcx, N>,
     method_def_id: DefId,
-) -> usize {
+) -> Option<usize> {
     let existential_trait_ref = object
         .upcast_trait_ref
         .map_bound(|trait_ref| ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref));
     let existential_trait_ref = tcx.erase_regions(existential_trait_ref);
+
     // Count number of methods preceding the one we are selecting and
     // add them to the total offset.
-    let index = tcx
+    if let Some(index) = tcx
         .own_existential_vtable_entries(existential_trait_ref)
         .iter()
         .copied()
         .position(|def_id| def_id == method_def_id)
-        .unwrap_or_else(|| {
-            bug!("get_vtable_index_of_object_method: {:?} was not found", method_def_id);
-        });
-    object.vtable_base + index
+    {
+        Some(object.vtable_base + index)
+    } else {
+        None
+    }
 }
 
 pub fn closure_trait_ref_and_return_type<'tcx>(
diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs
index 9eea02b..8d66604 100644
--- a/compiler/rustc_trait_selection/src/traits/wf.rs
+++ b/compiler/rustc_trait_selection/src/traits/wf.rs
@@ -41,7 +41,7 @@
             .into()
         }
         GenericArgKind::Const(ct) => {
-            match ct.val() {
+            match ct.kind() {
                 ty::ConstKind::Infer(infer) => {
                     let resolved = infcx.shallow_resolve(infer);
                     if resolved == infer {
@@ -51,7 +51,7 @@
 
                     infcx
                         .tcx
-                        .mk_const(ty::ConstS { val: ty::ConstKind::Infer(resolved), ty: ct.ty() })
+                        .mk_const(ty::ConstS { kind: ty::ConstKind::Infer(resolved), ty: ct.ty() })
                 }
                 _ => ct,
             }
@@ -81,10 +81,17 @@
     body_id: hir::HirId,
     trait_ref: &ty::TraitRef<'tcx>,
     span: Span,
-    item: Option<&'tcx hir::Item<'tcx>>,
+    item: &'tcx hir::Item<'tcx>,
 ) -> Vec<traits::PredicateObligation<'tcx>> {
-    let mut wf =
-        WfPredicates { infcx, param_env, body_id, span, out: vec![], recursion_depth: 0, item };
+    let mut wf = WfPredicates {
+        infcx,
+        param_env,
+        body_id,
+        span,
+        out: vec![],
+        recursion_depth: 0,
+        item: Some(item),
+    };
     wf.compute_trait_ref(trait_ref, Elaborate::All);
     debug!(obligations = ?wf.out);
     wf.normalize()
@@ -294,30 +301,22 @@
         let obligations = self.nominal_obligations(trait_ref.def_id, trait_ref.substs);
 
         debug!("compute_trait_ref obligations {:?}", obligations);
-        let cause = self.cause(traits::MiscObligation);
         let param_env = self.param_env;
         let depth = self.recursion_depth;
 
         let item = self.item;
 
-        let extend = |obligation: traits::PredicateObligation<'tcx>| {
-            let mut cause = cause.clone();
-            if let Some(parent_trait_pred) = obligation.predicate.to_opt_poly_trait_pred() {
-                let derived_cause = traits::DerivedObligationCause {
+        let extend = |traits::PredicateObligation { predicate, mut cause, .. }| {
+            if let Some(parent_trait_pred) = predicate.to_opt_poly_trait_pred() {
+                cause = cause.derived_cause(
                     parent_trait_pred,
-                    parent_code: obligation.cause.clone_code(),
-                };
-                *cause.make_mut_code() =
-                    traits::ObligationCauseCode::DerivedObligation(derived_cause);
+                    traits::ObligationCauseCode::DerivedObligation,
+                );
             }
             extend_cause_with_original_assoc_item_obligation(
-                tcx,
-                trait_ref,
-                item,
-                &mut cause,
-                obligation.predicate,
+                tcx, trait_ref, item, &mut cause, predicate,
             );
-            traits::Obligation::with_depth(cause, depth, param_env, obligation.predicate)
+            traits::Obligation::with_depth(cause, depth, param_env, predicate)
         };
 
         if let Elaborate::All = elaborate {
@@ -339,17 +338,17 @@
                 })
                 .filter(|(_, arg)| !arg.has_escaping_bound_vars())
                 .map(|(i, arg)| {
-                    let mut new_cause = cause.clone();
+                    let mut cause = traits::ObligationCause::misc(self.span, self.body_id);
                     // The first subst is the self ty - use the correct span for it.
                     if i == 0 {
                         if let Some(hir::ItemKind::Impl(hir::Impl { self_ty, .. })) =
                             item.map(|i| &i.kind)
                         {
-                            new_cause.span = self_ty.span;
+                            cause.span = self_ty.span;
                         }
                     }
                     traits::Obligation::with_depth(
-                        new_cause,
+                        cause,
                         depth,
                         param_env,
                         ty::Binder::dummy(ty::PredicateKind::WellFormed(arg)).to_predicate(tcx),
@@ -438,7 +437,7 @@
                 GenericArgKind::Lifetime(_) => continue,
 
                 GenericArgKind::Const(constant) => {
-                    match constant.val() {
+                    match constant.kind() {
                         ty::ConstKind::Unevaluated(uv) => {
                             let obligations = self.nominal_obligations(uv.def.did, uv.substs);
                             self.out.extend(obligations);
@@ -461,7 +460,7 @@
                                 let cause = self.cause(traits::MiscObligation);
 
                                 let resolved_constant = self.infcx.tcx.mk_const(ty::ConstS {
-                                    val: ty::ConstKind::Infer(resolved),
+                                    kind: ty::ConstKind::Infer(resolved),
                                     ty: constant.ty(),
                                 });
                                 self.out.push(traits::Obligation::with_depth(
@@ -575,7 +574,7 @@
                     // generators don't take arguments.
                 }
 
-                ty::Closure(_, substs) => {
+                ty::Closure(did, substs) => {
                     // Only check the upvar types for WF, not the rest
                     // of the types within. This is needed because we
                     // capture the signature and it may not be WF
@@ -614,10 +613,8 @@
                     // can cause compiler crashes when the user abuses unsafe
                     // code to procure such a closure.
                     // See src/test/ui/type-alias-impl-trait/wf_check_closures.rs
-                    // We should be checking the nominal_obligations here, but that caused
-                    // a regression in https://github.com/rust-lang/rust/issues/97607
-                    // The regression will be fixed on nightly, but the fix is too large
-                    // to be backported.
+                    let obligations = self.nominal_obligations(did, substs);
+                    self.out.extend(obligations);
                 }
 
                 ty::FnPtr(_) => {
diff --git a/compiler/rustc_traits/src/chalk/db.rs b/compiler/rustc_traits/src/chalk/db.rs
index 5b5b849..497819c 100644
--- a/compiler/rustc_traits/src/chalk/db.rs
+++ b/compiler/rustc_traits/src/chalk/db.rs
@@ -9,7 +9,7 @@
 use rustc_middle::traits::ChalkRustInterner as RustInterner;
 use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef};
 use rustc_middle::ty::{
-    self, AssocItemContainer, AssocKind, EarlyBinder, Ty, TyCtxt, TypeFoldable,
+    self, AssocItemContainer, AssocKind, EarlyBinder, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable,
 };
 
 use rustc_ast::ast;
@@ -736,7 +736,7 @@
 
         ty::GenericParamDefKind::Const { .. } => tcx
             .mk_const(ty::ConstS {
-                val: ty::ConstKind::Bound(ty::INNERMOST, ty::BoundVar::from(param.index)),
+                kind: ty::ConstKind::Bound(ty::INNERMOST, ty::BoundVar::from(param.index)),
                 ty: tcx.type_of(param.def_id),
             })
             .into(),
diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs
index e3c865c..e9f05ce 100644
--- a/compiler/rustc_traits/src/chalk/lowering.rs
+++ b/compiler/rustc_traits/src/chalk/lowering.rs
@@ -33,9 +33,10 @@
 
 use rustc_ast::ast;
 use rustc_middle::traits::{ChalkEnvironmentAndGoal, ChalkRustInterner as RustInterner};
-use rustc_middle::ty::fold::TypeFolder;
 use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef};
-use rustc_middle::ty::{self, Binder, Region, Ty, TyCtxt, TypeFoldable, TypeVisitor};
+use rustc_middle::ty::{
+    self, Binder, Region, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitor,
+};
 use rustc_span::def_id::DefId;
 
 use chalk_ir::{FnSig, ForeignDefId};
@@ -44,7 +45,7 @@
 use std::ops::ControlFlow;
 
 /// Essentially an `Into` with a `&RustInterner` parameter
-crate trait LowerInto<'tcx, T> {
+pub(crate) trait LowerInto<'tcx, T> {
     /// Lower a rustc construct (e.g., `ty::TraitPredicate`) to a chalk type, consuming `self`.
     fn lower_into(self, interner: RustInterner<'tcx>) -> T;
 }
@@ -513,7 +514,7 @@
 impl<'tcx> LowerInto<'tcx, chalk_ir::Const<RustInterner<'tcx>>> for ty::Const<'tcx> {
     fn lower_into(self, interner: RustInterner<'tcx>) -> chalk_ir::Const<RustInterner<'tcx>> {
         let ty = self.ty().lower_into(interner);
-        let value = match self.val() {
+        let value = match self.kind() {
             ty::ConstKind::Value(val) => {
                 chalk_ir::ConstValue::Concrete(chalk_ir::ConcreteConst { interned: val })
             }
@@ -530,7 +531,7 @@
     fn lower_into(self, interner: RustInterner<'tcx>) -> ty::Const<'tcx> {
         let data = self.data(interner);
         let ty = data.ty.lower_into(interner);
-        let val = match data.value {
+        let kind = match data.value {
             chalk_ir::ConstValue::BoundVar(var) => ty::ConstKind::Bound(
                 ty::DebruijnIndex::from_u32(var.debruijn.depth()),
                 ty::BoundVar::from_u32(var.index as u32),
@@ -539,7 +540,7 @@
             chalk_ir::ConstValue::Placeholder(_p) => unimplemented!(),
             chalk_ir::ConstValue::Concrete(c) => ty::ConstKind::Value(c.interned),
         };
-        interner.tcx.mk_const(ty::ConstS { ty, val })
+        interner.tcx.mk_const(ty::ConstS { ty, kind })
     }
 }
 
@@ -836,7 +837,7 @@
 /// It's important to note that because of prior substitution, we may have
 /// late-bound regions, even outside of fn contexts, since this is the best way
 /// to prep types for chalk lowering.
-crate fn collect_bound_vars<'tcx, T: TypeFoldable<'tcx>>(
+pub(crate) fn collect_bound_vars<'tcx, T: TypeFoldable<'tcx>>(
     interner: RustInterner<'tcx>,
     tcx: TyCtxt<'tcx>,
     ty: Binder<'tcx, T>,
@@ -870,14 +871,14 @@
     (new_ty, binders, named_parameters)
 }
 
-crate struct BoundVarsCollector<'tcx> {
+pub(crate) struct BoundVarsCollector<'tcx> {
     binder_index: ty::DebruijnIndex,
-    crate parameters: BTreeMap<u32, chalk_ir::VariableKind<RustInterner<'tcx>>>,
-    crate named_parameters: Vec<DefId>,
+    pub(crate) parameters: BTreeMap<u32, chalk_ir::VariableKind<RustInterner<'tcx>>>,
+    pub(crate) named_parameters: Vec<DefId>,
 }
 
 impl<'tcx> BoundVarsCollector<'tcx> {
-    crate fn new() -> Self {
+    pub(crate) fn new() -> Self {
         BoundVarsCollector {
             binder_index: ty::INNERMOST,
             parameters: BTreeMap::new(),
@@ -1001,17 +1002,17 @@
 
 /// Used to substitute `Param`s with placeholders. We do this since Chalk
 /// have a notion of `Param`s.
-crate struct ParamsSubstitutor<'tcx> {
+pub(crate) struct ParamsSubstitutor<'tcx> {
     tcx: TyCtxt<'tcx>,
     binder_index: ty::DebruijnIndex,
     list: Vec<rustc_middle::ty::ParamTy>,
     next_ty_placeholder: usize,
-    crate params: rustc_data_structures::fx::FxHashMap<usize, rustc_middle::ty::ParamTy>,
-    crate named_regions: BTreeMap<DefId, u32>,
+    pub(crate) params: rustc_data_structures::fx::FxHashMap<usize, rustc_middle::ty::ParamTy>,
+    pub(crate) named_regions: BTreeMap<DefId, u32>,
 }
 
 impl<'tcx> ParamsSubstitutor<'tcx> {
-    crate fn new(tcx: TyCtxt<'tcx>, next_ty_placeholder: usize) -> Self {
+    pub(crate) fn new(tcx: TyCtxt<'tcx>, next_ty_placeholder: usize) -> Self {
         ParamsSubstitutor {
             tcx,
             binder_index: ty::INNERMOST,
@@ -1083,13 +1084,13 @@
     }
 }
 
-crate struct ReverseParamsSubstitutor<'tcx> {
+pub(crate) struct ReverseParamsSubstitutor<'tcx> {
     tcx: TyCtxt<'tcx>,
     params: rustc_data_structures::fx::FxHashMap<usize, rustc_middle::ty::ParamTy>,
 }
 
 impl<'tcx> ReverseParamsSubstitutor<'tcx> {
-    crate fn new(
+    pub(crate) fn new(
         tcx: TyCtxt<'tcx>,
         params: rustc_data_structures::fx::FxHashMap<usize, rustc_middle::ty::ParamTy>,
     ) -> Self {
@@ -1117,14 +1118,14 @@
 }
 
 /// Used to collect `Placeholder`s.
-crate struct PlaceholdersCollector {
+pub(crate) struct PlaceholdersCollector {
     universe_index: ty::UniverseIndex,
-    crate next_ty_placeholder: usize,
-    crate next_anon_region_placeholder: u32,
+    pub(crate) next_ty_placeholder: usize,
+    pub(crate) next_anon_region_placeholder: u32,
 }
 
 impl PlaceholdersCollector {
-    crate fn new() -> Self {
+    pub(crate) fn new() -> Self {
         PlaceholdersCollector {
             universe_index: ty::UniverseIndex::ROOT,
             next_ty_placeholder: 0,
diff --git a/compiler/rustc_traits/src/chalk/mod.rs b/compiler/rustc_traits/src/chalk/mod.rs
index 4e19479..59cf37f 100644
--- a/compiler/rustc_traits/src/chalk/mod.rs
+++ b/compiler/rustc_traits/src/chalk/mod.rs
@@ -3,8 +3,8 @@
 //! In order to call `chalk-solve`, this file must convert a `CanonicalChalkEnvironmentAndGoal` into
 //! a Chalk uncanonical goal. It then calls Chalk, and converts the answer back into rustc solution.
 
-crate mod db;
-crate mod lowering;
+pub(crate) mod db;
+pub(crate) mod lowering;
 
 use rustc_data_structures::fx::FxHashMap;
 
@@ -27,11 +27,11 @@
 
 use chalk_solve::Solution;
 
-crate fn provide(p: &mut Providers) {
+pub(crate) fn provide(p: &mut Providers) {
     *p = Providers { evaluate_goal, ..*p };
 }
 
-crate fn evaluate_goal<'tcx>(
+pub(crate) fn evaluate_goal<'tcx>(
     tcx: TyCtxt<'tcx>,
     obligation: CanonicalChalkEnvironmentAndGoal<'tcx>,
 ) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, ()>>, traits::query::NoSolution> {
diff --git a/compiler/rustc_traits/src/dropck_outlives.rs b/compiler/rustc_traits/src/dropck_outlives.rs
index 3fd0bb1..a20de08 100644
--- a/compiler/rustc_traits/src/dropck_outlives.rs
+++ b/compiler/rustc_traits/src/dropck_outlives.rs
@@ -17,7 +17,7 @@
     Normalized, ObligationCause, TraitEngine, TraitEngineExt as _,
 };
 
-crate fn provide(p: &mut Providers) {
+pub(crate) fn provide(p: &mut Providers) {
     *p = Providers { dropck_outlives, adt_dtorck_constraint, ..*p };
 }
 
@@ -304,7 +304,7 @@
 }
 
 /// Calculates the dtorck constraint for a type.
-crate fn adt_dtorck_constraint(
+pub(crate) fn adt_dtorck_constraint(
     tcx: TyCtxt<'_>,
     def_id: DefId,
 ) -> Result<&DropckConstraint<'_>, NoSolution> {
diff --git a/compiler/rustc_traits/src/evaluate_obligation.rs b/compiler/rustc_traits/src/evaluate_obligation.rs
index 2404b7f..3fc1414 100644
--- a/compiler/rustc_traits/src/evaluate_obligation.rs
+++ b/compiler/rustc_traits/src/evaluate_obligation.rs
@@ -7,7 +7,7 @@
     EvaluationResult, Obligation, ObligationCause, OverflowError, SelectionContext, TraitQueryMode,
 };
 
-crate fn provide(p: &mut Providers) {
+pub(crate) fn provide(p: &mut Providers) {
     *p = Providers { evaluate_obligation, ..*p };
 }
 
diff --git a/compiler/rustc_traits/src/implied_outlives_bounds.rs b/compiler/rustc_traits/src/implied_outlives_bounds.rs
index 90c698d..9653241 100644
--- a/compiler/rustc_traits/src/implied_outlives_bounds.rs
+++ b/compiler/rustc_traits/src/implied_outlives_bounds.rs
@@ -18,7 +18,7 @@
 use rustc_trait_selection::traits::TraitEngine;
 use smallvec::{smallvec, SmallVec};
 
-crate fn provide(p: &mut Providers) {
+pub(crate) fn provide(p: &mut Providers) {
     *p = Providers { implied_outlives_bounds, ..*p };
 }
 
diff --git a/compiler/rustc_traits/src/lib.rs b/compiler/rustc_traits/src/lib.rs
index 73fd95e..2bea164 100644
--- a/compiler/rustc_traits/src/lib.rs
+++ b/compiler/rustc_traits/src/lib.rs
@@ -1,9 +1,7 @@
 //! New recursive solver modeled on Chalk's recursive solver. Most of
 //! the guts are broken up into modules; see the comments in those modules.
 
-#![feature(crate_visibility_modifier)]
 #![feature(let_else)]
-#![feature(nll)]
 #![recursion_limit = "256"]
 
 #[macro_use]
diff --git a/compiler/rustc_traits/src/normalize_erasing_regions.rs b/compiler/rustc_traits/src/normalize_erasing_regions.rs
index a4aa965..5d394ed 100644
--- a/compiler/rustc_traits/src/normalize_erasing_regions.rs
+++ b/compiler/rustc_traits/src/normalize_erasing_regions.rs
@@ -6,7 +6,7 @@
 use rustc_trait_selection::traits::{Normalized, ObligationCause};
 use std::sync::atomic::Ordering;
 
-crate fn provide(p: &mut Providers) {
+pub(crate) fn provide(p: &mut Providers) {
     *p = Providers {
         try_normalize_generic_arg_after_erasing_regions: |tcx, goal| {
             debug!("try_normalize_generic_arg_after_erasing_regions(goal={:#?}", goal);
@@ -25,7 +25,6 @@
     };
 }
 
-#[instrument(level = "debug", skip(tcx))]
 fn try_normalize_after_erasing_regions<'tcx, T: TypeFoldable<'tcx> + PartialEq + Copy>(
     tcx: TyCtxt<'tcx>,
     goal: ParamEnvAnd<'tcx, T>,
diff --git a/compiler/rustc_traits/src/normalize_projection_ty.rs b/compiler/rustc_traits/src/normalize_projection_ty.rs
index 1de50ba..98bb42c 100644
--- a/compiler/rustc_traits/src/normalize_projection_ty.rs
+++ b/compiler/rustc_traits/src/normalize_projection_ty.rs
@@ -10,7 +10,7 @@
 use rustc_trait_selection::traits::{self, ObligationCause, SelectionContext};
 use std::sync::atomic::Ordering;
 
-crate fn provide(p: &mut Providers) {
+pub(crate) fn provide(p: &mut Providers) {
     *p = Providers { normalize_projection_ty, ..*p };
 }
 
diff --git a/compiler/rustc_traits/src/type_op.rs b/compiler/rustc_traits/src/type_op.rs
index 861d3bc..f8bac1d 100644
--- a/compiler/rustc_traits/src/type_op.rs
+++ b/compiler/rustc_traits/src/type_op.rs
@@ -23,7 +23,7 @@
 use rustc_trait_selection::traits::{Normalized, Obligation, ObligationCause, TraitEngine};
 use std::fmt;
 
-crate fn provide(p: &mut Providers) {
+pub(crate) fn provide(p: &mut Providers) {
     *p = Providers {
         type_op_ascribe_user_type,
         type_op_eq,
diff --git a/compiler/rustc_ty_utils/Cargo.toml b/compiler/rustc_ty_utils/Cargo.toml
index 78df95e..d03d675 100644
--- a/compiler/rustc_ty_utils/Cargo.toml
+++ b/compiler/rustc_ty_utils/Cargo.toml
@@ -14,3 +14,4 @@
 rustc_session = { path = "../rustc_session" }
 rustc_target = { path = "../rustc_target" }
 rustc_trait_selection = { path = "../rustc_trait_selection" }
+rustc_type_ir = { path = "../rustc_type_ir" }
diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs
index 143081d..552db54 100644
--- a/compiler/rustc_ty_utils/src/instance.rs
+++ b/compiler/rustc_ty_utils/src/instance.rs
@@ -3,9 +3,10 @@
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_middle::traits::CodegenObligationError;
 use rustc_middle::ty::subst::SubstsRef;
-use rustc_middle::ty::{self, Binder, Instance, Ty, TyCtxt, TypeFoldable, TypeVisitor};
+use rustc_middle::ty::{
+    self, Binder, Instance, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable, TypeVisitor,
+};
 use rustc_span::{sym, DUMMY_SP};
-use rustc_target::spec::abi::Abi;
 use rustc_trait_selection::traits;
 use traits::{translate_substs, Reveal};
 
@@ -111,7 +112,6 @@
     }
 }
 
-#[instrument(level = "debug", skip(tcx))]
 fn resolve_instance<'tcx>(
     tcx: TyCtxt<'tcx>,
     key: ty::ParamEnvAnd<'tcx, (DefId, SubstsRef<'tcx>)>,
@@ -140,7 +140,6 @@
     )
 }
 
-#[instrument(level = "debug", skip(tcx))]
 fn inner_resolve_instance<'tcx>(
     tcx: TyCtxt<'tcx>,
     key: ty::ParamEnvAnd<'tcx, (ty::WithOptConstParam<DefId>, SubstsRef<'tcx>)>,
@@ -155,12 +154,7 @@
         let item_type = tcx.subst_and_normalize_erasing_regions(substs, param_env, ty);
 
         let def = match *item_type.kind() {
-            ty::FnDef(..)
-                if {
-                    let f = item_type.fn_sig(tcx);
-                    f.abi() == Abi::RustIntrinsic || f.abi() == Abi::PlatformIntrinsic
-                } =>
-            {
+            ty::FnDef(def_id, ..) if tcx.is_intrinsic(def_id) => {
                 debug!(" => intrinsic");
                 ty::InstanceDef::Intrinsic(def.did)
             }
@@ -353,11 +347,15 @@
             _ => None,
         },
         traits::ImplSource::Object(ref data) => {
-            let index = traits::get_vtable_index_of_object_method(tcx, data, trait_item_id);
-            Some(Instance {
-                def: ty::InstanceDef::Virtual(trait_item_id, index),
-                substs: rcvr_substs,
-            })
+            if let Some(index) = traits::get_vtable_index_of_object_method(tcx, data, trait_item_id)
+            {
+                Some(Instance {
+                    def: ty::InstanceDef::Virtual(trait_item_id, index),
+                    substs: rcvr_substs,
+                })
+            } else {
+                None
+            }
         }
         traits::ImplSource::Builtin(..) => {
             if Some(trait_ref.def_id) == tcx.lang_items().clone_trait() {
diff --git a/compiler/rustc_ty_utils/src/lib.rs b/compiler/rustc_ty_utils/src/lib.rs
index 702a951..484967b 100644
--- a/compiler/rustc_ty_utils/src/lib.rs
+++ b/compiler/rustc_ty_utils/src/lib.rs
@@ -7,7 +7,6 @@
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![feature(control_flow_enum)]
 #![feature(let_else)]
-#![feature(nll)]
 #![recursion_limit = "256"]
 
 #[macro_use]
diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs
index 23700e6..38ae6a2 100644
--- a/compiler/rustc_ty_utils/src/ty.rs
+++ b/compiler/rustc_ty_utils/src/ty.rs
@@ -5,7 +5,6 @@
 use rustc_middle::ty::{
     self, Binder, EarlyBinder, Predicate, PredicateKind, ToPredicate, Ty, TyCtxt,
 };
-use rustc_span::{sym, Span};
 use rustc_trait_selection::traits;
 
 fn sized_constraint_for_ty<'tcx>(
@@ -13,7 +12,7 @@
     adtdef: ty::AdtDef<'tcx>,
     ty: Ty<'tcx>,
 ) -> Vec<Ty<'tcx>> {
-    use ty::TyKind::*;
+    use rustc_type_ir::sty::TyKind::*;
 
     let result = match ty.kind() {
         Bool | Char | Int(..) | Uint(..) | Float(..) | RawPtr(..) | Ref(..) | FnDef(..)
@@ -103,21 +102,6 @@
     ty::AdtSizedConstraint(result)
 }
 
-fn def_ident_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Span> {
-    tcx.hir()
-        .get_if_local(def_id)
-        .and_then(|node| match node {
-            // A `Ctor` doesn't have an identifier itself, but its parent
-            // struct/variant does. Compare with `hir::Map::opt_span`.
-            hir::Node::Ctor(ctor) => ctor
-                .ctor_hir_id()
-                .and_then(|ctor_id| tcx.hir().find(tcx.hir().get_parent_node(ctor_id)))
-                .and_then(|parent| parent.ident()),
-            _ => node.ident(),
-        })
-        .map(|ident| ident.span)
-}
-
 /// See `ParamEnv` struct definition for details.
 #[instrument(level = "debug", skip(tcx))]
 fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> {
@@ -153,7 +137,7 @@
     let constness = match hir_id {
         Some(hir_id) => match tcx.hir().get(hir_id) {
             hir::Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Fn(..), .. })
-                if tcx.has_attr(def_id, sym::default_method_body_is_const) =>
+                if tcx.is_const_default_method(def_id) =>
             {
                 hir::Constness::Const
             }
@@ -480,7 +464,6 @@
     *providers = ty::query::Providers {
         asyncness,
         adt_sized_constraint,
-        def_ident_span,
         param_env,
         param_env_reveal_all_normalized,
         instance_def_size_estimate,
diff --git a/compiler/rustc_type_ir/Cargo.toml b/compiler/rustc_type_ir/Cargo.toml
index 439e6cd..b8066f2 100644
--- a/compiler/rustc_type_ir/Cargo.toml
+++ b/compiler/rustc_type_ir/Cargo.toml
@@ -12,3 +12,4 @@
 rustc_serialize = { path = "../rustc_serialize" }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_macros = { path = "../rustc_macros" }
+smallvec = { version = "1.0", features = ["union", "may_dangle"] }
diff --git a/compiler/rustc_type_ir/src/codec.rs b/compiler/rustc_type_ir/src/codec.rs
new file mode 100644
index 0000000..6a9ea79
--- /dev/null
+++ b/compiler/rustc_type_ir/src/codec.rs
@@ -0,0 +1,64 @@
+use crate::Interner;
+
+use rustc_data_structures::stable_map::FxHashMap;
+use rustc_serialize::{Decoder, Encoder};
+
+/// The shorthand encoding uses an enum's variant index `usize`
+/// and is offset by this value so it never matches a real variant.
+/// This offset is also chosen so that the first byte is never < 0x80.
+pub const SHORTHAND_OFFSET: usize = 0x80;
+
+/// Trait for decoding to a reference.
+///
+/// This is a separate trait from `Decodable` so that we can implement it for
+/// upstream types, such as `FxHashSet`.
+///
+/// The `TyDecodable` derive macro will use this trait for fields that are
+/// references (and don't use a type alias to hide that).
+///
+/// `Decodable` can still be implemented in cases where `Decodable` is required
+/// by a trait bound.
+pub trait RefDecodable<'tcx, D: TyDecoder> {
+    fn decode(d: &mut D) -> &'tcx Self;
+}
+
+pub trait TyEncoder: Encoder {
+    type I: Interner;
+    const CLEAR_CROSS_CRATE: bool;
+
+    fn position(&self) -> usize;
+    fn type_shorthands(&mut self) -> &mut FxHashMap<<Self::I as Interner>::Ty, usize>;
+    fn predicate_shorthands(
+        &mut self,
+    ) -> &mut FxHashMap<<Self::I as Interner>::PredicateKind, usize>;
+    fn encode_alloc_id(&mut self, alloc_id: &<Self::I as Interner>::AllocId);
+}
+
+pub trait TyDecoder: Decoder {
+    type I: Interner;
+    const CLEAR_CROSS_CRATE: bool;
+
+    fn interner(&self) -> Self::I;
+
+    fn peek_byte(&self) -> u8;
+
+    fn position(&self) -> usize;
+
+    fn cached_ty_for_shorthand<F>(
+        &mut self,
+        shorthand: usize,
+        or_insert_with: F,
+    ) -> <Self::I as Interner>::Ty
+    where
+        F: FnOnce(&mut Self) -> <Self::I as Interner>::Ty;
+
+    fn with_position<F, R>(&mut self, pos: usize, f: F) -> R
+    where
+        F: FnOnce(&mut Self) -> R;
+
+    fn positioned_at_shorthand(&self) -> bool {
+        (self.peek_byte() & (SHORTHAND_OFFSET as u8)) != 0
+    }
+
+    fn decode_alloc_id(&mut self) -> <Self::I as Interner>::AllocId;
+}
diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs
index c63e9c3..fe9a155 100644
--- a/compiler/rustc_type_ir/src/lib.rs
+++ b/compiler/rustc_type_ir/src/lib.rs
@@ -1,4 +1,5 @@
 #![feature(min_specialization)]
+#![feature(rustc_attrs)]
 
 #[macro_use]
 extern crate bitflags;
@@ -7,9 +8,150 @@
 
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_data_structures::unify::{EqUnifyValue, UnifyKey};
+use smallvec::SmallVec;
 use std::fmt;
+use std::fmt::Debug;
+use std::hash::Hash;
 use std::mem::discriminant;
 
+pub mod codec;
+pub mod sty;
+
+pub use codec::*;
+pub use sty::*;
+
+pub trait Interner {
+    type AdtDef: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
+    type SubstsRef: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
+    type DefId: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
+    type Ty: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
+    type Const: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
+    type Region: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
+    type TypeAndMut: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
+    type Mutability: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
+    type Movability: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
+    type PolyFnSig: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
+    type ListBinderExistentialPredicate: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
+    type BinderListTy: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
+    type ListTy: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
+    type ProjectionTy: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
+    type ParamTy: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
+    type BoundTy: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
+    type PlaceholderType: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
+    type InferTy: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
+    type DelaySpanBugEmitted: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
+    type PredicateKind: Clone + Debug + Hash + PartialEq + Eq;
+    type AllocId: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
+
+    type EarlyBoundRegion: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
+    type BoundRegion: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
+    type FreeRegion: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
+    type RegionVid: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
+    type PlaceholderRegion: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
+}
+
+pub trait InternAs<T: ?Sized, R> {
+    type Output;
+    fn intern_with<F>(self, f: F) -> Self::Output
+    where
+        F: FnOnce(&T) -> R;
+}
+
+impl<I, T, R, E> InternAs<[T], R> for I
+where
+    E: InternIteratorElement<T, R>,
+    I: Iterator<Item = E>,
+{
+    type Output = E::Output;
+    fn intern_with<F>(self, f: F) -> Self::Output
+    where
+        F: FnOnce(&[T]) -> R,
+    {
+        E::intern_with(self, f)
+    }
+}
+
+pub trait InternIteratorElement<T, R>: Sized {
+    type Output;
+    fn intern_with<I: Iterator<Item = Self>, F: FnOnce(&[T]) -> R>(iter: I, f: F) -> Self::Output;
+}
+
+impl<T, R> InternIteratorElement<T, R> for T {
+    type Output = R;
+    fn intern_with<I: Iterator<Item = Self>, F: FnOnce(&[T]) -> R>(
+        mut iter: I,
+        f: F,
+    ) -> Self::Output {
+        // This code is hot enough that it's worth specializing for the most
+        // common length lists, to avoid the overhead of `SmallVec` creation.
+        // Lengths 0, 1, and 2 typically account for ~95% of cases. If
+        // `size_hint` is incorrect a panic will occur via an `unwrap` or an
+        // `assert`.
+        match iter.size_hint() {
+            (0, Some(0)) => {
+                assert!(iter.next().is_none());
+                f(&[])
+            }
+            (1, Some(1)) => {
+                let t0 = iter.next().unwrap();
+                assert!(iter.next().is_none());
+                f(&[t0])
+            }
+            (2, Some(2)) => {
+                let t0 = iter.next().unwrap();
+                let t1 = iter.next().unwrap();
+                assert!(iter.next().is_none());
+                f(&[t0, t1])
+            }
+            _ => f(&iter.collect::<SmallVec<[_; 8]>>()),
+        }
+    }
+}
+
+impl<'a, T, R> InternIteratorElement<T, R> for &'a T
+where
+    T: Clone + 'a,
+{
+    type Output = R;
+    fn intern_with<I: Iterator<Item = Self>, F: FnOnce(&[T]) -> R>(iter: I, f: F) -> Self::Output {
+        // This code isn't hot.
+        f(&iter.cloned().collect::<SmallVec<[_; 8]>>())
+    }
+}
+
+impl<T, R, E> InternIteratorElement<T, R> for Result<T, E> {
+    type Output = Result<R, E>;
+    fn intern_with<I: Iterator<Item = Self>, F: FnOnce(&[T]) -> R>(
+        mut iter: I,
+        f: F,
+    ) -> Self::Output {
+        // This code is hot enough that it's worth specializing for the most
+        // common length lists, to avoid the overhead of `SmallVec` creation.
+        // Lengths 0, 1, and 2 typically account for ~95% of cases. If
+        // `size_hint` is incorrect a panic will occur via an `unwrap` or an
+        // `assert`, unless a failure happens first, in which case the result
+        // will be an error anyway.
+        Ok(match iter.size_hint() {
+            (0, Some(0)) => {
+                assert!(iter.next().is_none());
+                f(&[])
+            }
+            (1, Some(1)) => {
+                let t0 = iter.next().unwrap()?;
+                assert!(iter.next().is_none());
+                f(&[t0])
+            }
+            (2, Some(2)) => {
+                let t0 = iter.next().unwrap()?;
+                let t1 = iter.next().unwrap()?;
+                assert!(iter.next().is_none());
+                f(&[t0, t1])
+            }
+            _ => f(&iter.collect::<Result<SmallVec<[_; 8]>, _>>()?),
+        })
+    }
+}
+
 bitflags! {
     /// Flags that we track on types. These flags are propagated upwards
     /// through the type during type construction, so that we can quickly check
@@ -61,14 +203,6 @@
                                           | TypeFlags::HAS_CT_INFER.bits
                                           | TypeFlags::HAS_TY_PLACEHOLDER.bits
                                           | TypeFlags::HAS_CT_PLACEHOLDER.bits
-                                          // The `evaluate_obligation` query does not return further
-                                          // obligations. If it evaluates an obligation with an opaque
-                                          // type, that opaque type may get compared to another type,
-                                          // constraining it. We would lose this information.
-                                          // FIXME: differentiate between crate-local opaque types
-                                          // and opaque types from other crates, as only opaque types
-                                          // from the local crate can possibly be a local name
-                                          | TypeFlags::HAS_TY_OPAQUE.bits
                                           // We consider 'freshened' types and constants
                                           // to depend on a particular fn.
                                           // The freshening process throws away information,
@@ -631,3 +765,85 @@
         }
     }
 }
+
+rustc_index::newtype_index! {
+    /// "Universes" are used during type- and trait-checking in the
+    /// presence of `for<..>` binders to control what sets of names are
+    /// visible. Universes are arranged into a tree: the root universe
+    /// contains names that are always visible. Each child then adds a new
+    /// set of names that are visible, in addition to those of its parent.
+    /// We say that the child universe "extends" the parent universe with
+    /// new names.
+    ///
+    /// To make this more concrete, consider this program:
+    ///
+    /// ```ignore (illustrative)
+    /// struct Foo { }
+    /// fn bar<T>(x: T) {
+    ///   let y: for<'a> fn(&'a u8, Foo) = ...;
+    /// }
+    /// ```
+    ///
+    /// The struct name `Foo` is in the root universe U0. But the type
+    /// parameter `T`, introduced on `bar`, is in an extended universe U1
+    /// -- i.e., within `bar`, we can name both `T` and `Foo`, but outside
+    /// of `bar`, we cannot name `T`. Then, within the type of `y`, the
+    /// region `'a` is in a universe U2 that extends U1, because we can
+    /// name it inside the fn type but not outside.
+    ///
+    /// Universes are used to do type- and trait-checking around these
+    /// "forall" binders (also called **universal quantification**). The
+    /// idea is that when, in the body of `bar`, we refer to `T` as a
+    /// type, we aren't referring to any type in particular, but rather a
+    /// kind of "fresh" type that is distinct from all other types we have
+    /// actually declared. This is called a **placeholder** type, and we
+    /// use universes to talk about this. In other words, a type name in
+    /// universe 0 always corresponds to some "ground" type that the user
+    /// declared, but a type name in a non-zero universe is a placeholder
+    /// type -- an idealized representative of "types in general" that we
+    /// use for checking generic functions.
+    pub struct UniverseIndex {
+        DEBUG_FORMAT = "U{}",
+    }
+}
+
+impl UniverseIndex {
+    pub const ROOT: UniverseIndex = UniverseIndex::from_u32(0);
+
+    /// Returns the "next" universe index in order -- this new index
+    /// is considered to extend all previous universes. This
+    /// corresponds to entering a `forall` quantifier. So, for
+    /// example, suppose we have this type in universe `U`:
+    ///
+    /// ```ignore (illustrative)
+    /// for<'a> fn(&'a u32)
+    /// ```
+    ///
+    /// Once we "enter" into this `for<'a>` quantifier, we are in a
+    /// new universe that extends `U` -- in this new universe, we can
+    /// name the region `'a`, but that region was not nameable from
+    /// `U` because it was not in scope there.
+    pub fn next_universe(self) -> UniverseIndex {
+        UniverseIndex::from_u32(self.private.checked_add(1).unwrap())
+    }
+
+    /// Returns `true` if `self` can name a name from `other` -- in other words,
+    /// if the set of names in `self` is a superset of those in
+    /// `other` (`self >= other`).
+    pub fn can_name(self, other: UniverseIndex) -> bool {
+        self.private >= other.private
+    }
+
+    /// Returns `true` if `self` cannot name some names from `other` -- in other
+    /// words, if the set of names in `self` is a strict subset of
+    /// those in `other` (`self < other`).
+    pub fn cannot_name(self, other: UniverseIndex) -> bool {
+        self.private < other.private
+    }
+}
+
+impl<CTX> HashStable<CTX> for UniverseIndex {
+    fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
+        self.private.hash_stable(ctx, hasher);
+    }
+}
diff --git a/compiler/rustc_type_ir/src/sty.rs b/compiler/rustc_type_ir/src/sty.rs
new file mode 100644
index 0000000..5cd2901
--- /dev/null
+++ b/compiler/rustc_type_ir/src/sty.rs
@@ -0,0 +1,1429 @@
+#![allow(rustc::usage_of_ty_tykind)]
+
+use std::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd};
+use std::{fmt, hash};
+
+use crate::DebruijnIndex;
+use crate::FloatTy;
+use crate::IntTy;
+use crate::Interner;
+use crate::TyDecoder;
+use crate::TyEncoder;
+use crate::UintTy;
+use crate::UniverseIndex;
+
+use self::RegionKind::*;
+use self::TyKind::*;
+
+use rustc_data_structures::stable_hasher::HashStable;
+use rustc_serialize::{Decodable, Decoder, Encodable};
+
+/// Defines the kinds of types used by the type system.
+///
+/// Types written by the user start out as `hir::TyKind` and get
+/// converted to this representation using `AstConv::ast_ty_to_ty`.
+#[rustc_diagnostic_item = "IrTyKind"]
+pub enum TyKind<I: Interner> {
+    /// The primitive boolean type. Written as `bool`.
+    Bool,
+
+    /// The primitive character type; holds a Unicode scalar value
+    /// (a non-surrogate code point). Written as `char`.
+    Char,
+
+    /// A primitive signed integer type. For example, `i32`.
+    Int(IntTy),
+
+    /// A primitive unsigned integer type. For example, `u32`.
+    Uint(UintTy),
+
+    /// A primitive floating-point type. For example, `f64`.
+    Float(FloatTy),
+
+    /// Algebraic data types (ADT). For example: structures, enumerations and unions.
+    ///
+    /// For example, the type `List<i32>` would be represented using the `AdtDef`
+    /// for `struct List<T>` and the substs `[i32]`.
+    ///
+    /// Note that generic parameters in fields only get lazily substituted
+    /// by using something like `adt_def.all_fields().map(|field| field.ty(tcx, substs))`.
+    Adt(I::AdtDef, I::SubstsRef),
+
+    /// An unsized FFI type that is opaque to Rust. Written as `extern type T`.
+    Foreign(I::DefId),
+
+    /// The pointee of a string slice. Written as `str`.
+    Str,
+
+    /// An array with the given length. Written as `[T; N]`.
+    Array(I::Ty, I::Const),
+
+    /// The pointee of an array slice. Written as `[T]`.
+    Slice(I::Ty),
+
+    /// A raw pointer. Written as `*mut T` or `*const T`
+    RawPtr(I::TypeAndMut),
+
+    /// A reference; a pointer with an associated lifetime. Written as
+    /// `&'a mut T` or `&'a T`.
+    Ref(I::Region, I::Ty, I::Mutability),
+
+    /// The anonymous type of a function declaration/definition. Each
+    /// function has a unique type.
+    ///
+    /// For the function `fn foo() -> i32 { 3 }` this type would be
+    /// shown to the user as `fn() -> i32 {foo}`.
+    ///
+    /// For example the type of `bar` here:
+    /// ```rust
+    /// fn foo() -> i32 { 1 }
+    /// let bar = foo; // bar: fn() -> i32 {foo}
+    /// ```
+    FnDef(I::DefId, I::SubstsRef),
+
+    /// A pointer to a function. Written as `fn() -> i32`.
+    ///
+    /// Note that both functions and closures start out as either
+    /// [FnDef] or [Closure] which can be then be coerced to this variant.
+    ///
+    /// For example the type of `bar` here:
+    ///
+    /// ```rust
+    /// fn foo() -> i32 { 1 }
+    /// let bar: fn() -> i32 = foo;
+    /// ```
+    FnPtr(I::PolyFnSig),
+
+    /// A trait object. Written as `dyn for<'b> Trait<'b, Assoc = u32> + Send + 'a`.
+    Dynamic(I::ListBinderExistentialPredicate, I::Region),
+
+    /// The anonymous type of a closure. Used to represent the type of `|a| a`.
+    ///
+    /// Closure substs contain both the - potentially substituted - generic parameters
+    /// of its parent and some synthetic parameters. See the documentation for
+    /// `ClosureSubsts` for more details.
+    Closure(I::DefId, I::SubstsRef),
+
+    /// The anonymous type of a generator. Used to represent the type of
+    /// `|a| yield a`.
+    ///
+    /// For more info about generator substs, visit the documentation for
+    /// `GeneratorSubsts`.
+    Generator(I::DefId, I::SubstsRef, I::Movability),
+
+    /// A type representing the types stored inside a generator.
+    /// This should only appear as part of the `GeneratorSubsts`.
+    ///
+    /// Note that the captured variables for generators are stored separately
+    /// using a tuple in the same way as for closures.
+    ///
+    /// Unlike upvars, the witness can reference lifetimes from
+    /// inside of the generator itself. To deal with them in
+    /// the type of the generator, we convert them to higher ranked
+    /// lifetimes bound by the witness itself.
+    ///
+    /// Looking at the following example, the witness for this generator
+    /// may end up as something like `for<'a> [Vec<i32>, &'a Vec<i32>]`:
+    ///
+    /// ```ignore UNSOLVED (ask @compiler-errors, should this error? can we just swap the yields?)
+    /// #![feature(generators)]
+    /// |a| {
+    ///     let x = &vec![3];
+    ///     yield a;
+    ///     yield x[0];
+    /// }
+    /// # ;
+    /// ```
+    GeneratorWitness(I::BinderListTy),
+
+    /// The never type `!`.
+    Never,
+
+    /// A tuple type. For example, `(i32, bool)`.
+    Tuple(I::ListTy),
+
+    /// The projection of an associated type. For example,
+    /// `<T as Trait<..>>::N`.
+    Projection(I::ProjectionTy),
+
+    /// Opaque (`impl Trait`) type found in a return type.
+    ///
+    /// The `DefId` comes either from
+    /// * the `impl Trait` ast::Ty node,
+    /// * or the `type Foo = impl Trait` declaration
+    ///
+    /// For RPIT the substitutions are for the generics of the function,
+    /// while for TAIT it is used for the generic parameters of the alias.
+    ///
+    /// During codegen, `tcx.type_of(def_id)` can be used to get the underlying type.
+    Opaque(I::DefId, I::SubstsRef),
+
+    /// A type parameter; for example, `T` in `fn f<T>(x: T) {}`.
+    Param(I::ParamTy),
+
+    /// Bound type variable, used to represent the `'a` in `for<'a> fn(&'a ())`.
+    ///
+    /// For canonical queries, we replace inference variables with bound variables,
+    /// so e.g. when checking whether `&'_ (): Trait<_>` holds, we canonicalize that to
+    /// `for<'a, T> &'a (): Trait<T>` and then convert the introduced bound variables
+    /// back to inference variables in a new inference context when inside of the query.
+    ///
+    /// See the `rustc-dev-guide` for more details about
+    /// [higher-ranked trait bounds][1] and [canonical queries][2].
+    ///
+    /// [1]: https://rustc-dev-guide.rust-lang.org/traits/hrtb.html
+    /// [2]: https://rustc-dev-guide.rust-lang.org/traits/canonical-queries.html
+    Bound(DebruijnIndex, I::BoundTy),
+
+    /// A placeholder type, used during higher ranked subtyping to instantiate
+    /// bound variables.
+    Placeholder(I::PlaceholderType),
+
+    /// A type variable used during type checking.
+    ///
+    /// Similar to placeholders, inference variables also live in a universe to
+    /// correctly deal with higher ranked types. Though unlike placeholders,
+    /// that universe is stored in the `InferCtxt` instead of directly
+    /// inside of the type.
+    Infer(I::InferTy),
+
+    /// A placeholder for a type which could not be computed; this is
+    /// propagated to avoid useless error messages.
+    Error(I::DelaySpanBugEmitted),
+}
+
+impl<I: Interner> TyKind<I> {
+    #[inline]
+    pub fn is_primitive(&self) -> bool {
+        matches!(self, Bool | Char | Int(_) | Uint(_) | Float(_))
+    }
+}
+
+// This is manually implemented for `TyKind` because `std::mem::discriminant`
+// returns an opaque value that is `PartialEq` but not `PartialOrd`
+#[inline]
+const fn tykind_discriminant<I: Interner>(value: &TyKind<I>) -> usize {
+    match value {
+        Bool => 0,
+        Char => 1,
+        Int(_) => 2,
+        Uint(_) => 3,
+        Float(_) => 4,
+        Adt(_, _) => 5,
+        Foreign(_) => 6,
+        Str => 7,
+        Array(_, _) => 8,
+        Slice(_) => 9,
+        RawPtr(_) => 10,
+        Ref(_, _, _) => 11,
+        FnDef(_, _) => 12,
+        FnPtr(_) => 13,
+        Dynamic(_, _) => 14,
+        Closure(_, _) => 15,
+        Generator(_, _, _) => 16,
+        GeneratorWitness(_) => 17,
+        Never => 18,
+        Tuple(_) => 19,
+        Projection(_) => 20,
+        Opaque(_, _) => 21,
+        Param(_) => 22,
+        Bound(_, _) => 23,
+        Placeholder(_) => 24,
+        Infer(_) => 25,
+        Error(_) => 26,
+    }
+}
+
+// This is manually implemented because a derive would require `I: Clone`
+impl<I: Interner> Clone for TyKind<I> {
+    fn clone(&self) -> Self {
+        match self {
+            Bool => Bool,
+            Char => Char,
+            Int(i) => Int(i.clone()),
+            Uint(u) => Uint(u.clone()),
+            Float(f) => Float(f.clone()),
+            Adt(d, s) => Adt(d.clone(), s.clone()),
+            Foreign(d) => Foreign(d.clone()),
+            Str => Str,
+            Array(t, c) => Array(t.clone(), c.clone()),
+            Slice(t) => Slice(t.clone()),
+            RawPtr(t) => RawPtr(t.clone()),
+            Ref(r, t, m) => Ref(r.clone(), t.clone(), m.clone()),
+            FnDef(d, s) => FnDef(d.clone(), s.clone()),
+            FnPtr(s) => FnPtr(s.clone()),
+            Dynamic(p, r) => Dynamic(p.clone(), r.clone()),
+            Closure(d, s) => Closure(d.clone(), s.clone()),
+            Generator(d, s, m) => Generator(d.clone(), s.clone(), m.clone()),
+            GeneratorWitness(g) => GeneratorWitness(g.clone()),
+            Never => Never,
+            Tuple(t) => Tuple(t.clone()),
+            Projection(p) => Projection(p.clone()),
+            Opaque(d, s) => Opaque(d.clone(), s.clone()),
+            Param(p) => Param(p.clone()),
+            Bound(d, b) => Bound(d.clone(), b.clone()),
+            Placeholder(p) => Placeholder(p.clone()),
+            Infer(t) => Infer(t.clone()),
+            Error(e) => Error(e.clone()),
+        }
+    }
+}
+
+// This is manually implemented because a derive would require `I: PartialEq`
+impl<I: Interner> PartialEq for TyKind<I> {
+    #[inline]
+    fn eq(&self, other: &TyKind<I>) -> bool {
+        let __self_vi = tykind_discriminant(self);
+        let __arg_1_vi = tykind_discriminant(other);
+        if __self_vi == __arg_1_vi {
+            match (&*self, &*other) {
+                (&Int(ref __self_0), &Int(ref __arg_1_0)) => __self_0 == __arg_1_0,
+                (&Uint(ref __self_0), &Uint(ref __arg_1_0)) => __self_0 == __arg_1_0,
+                (&Float(ref __self_0), &Float(ref __arg_1_0)) => __self_0 == __arg_1_0,
+                (&Adt(ref __self_0, ref __self_1), &Adt(ref __arg_1_0, ref __arg_1_1)) => {
+                    __self_0 == __arg_1_0 && __self_1 == __arg_1_1
+                }
+                (&Foreign(ref __self_0), &Foreign(ref __arg_1_0)) => __self_0 == __arg_1_0,
+                (&Array(ref __self_0, ref __self_1), &Array(ref __arg_1_0, ref __arg_1_1)) => {
+                    __self_0 == __arg_1_0 && __self_1 == __arg_1_1
+                }
+                (&Slice(ref __self_0), &Slice(ref __arg_1_0)) => __self_0 == __arg_1_0,
+                (&RawPtr(ref __self_0), &RawPtr(ref __arg_1_0)) => __self_0 == __arg_1_0,
+                (
+                    &Ref(ref __self_0, ref __self_1, ref __self_2),
+                    &Ref(ref __arg_1_0, ref __arg_1_1, ref __arg_1_2),
+                ) => __self_0 == __arg_1_0 && __self_1 == __arg_1_1 && __self_2 == __arg_1_2,
+                (&FnDef(ref __self_0, ref __self_1), &FnDef(ref __arg_1_0, ref __arg_1_1)) => {
+                    __self_0 == __arg_1_0 && __self_1 == __arg_1_1
+                }
+                (&FnPtr(ref __self_0), &FnPtr(ref __arg_1_0)) => __self_0 == __arg_1_0,
+                (&Dynamic(ref __self_0, ref __self_1), &Dynamic(ref __arg_1_0, ref __arg_1_1)) => {
+                    __self_0 == __arg_1_0 && __self_1 == __arg_1_1
+                }
+                (&Closure(ref __self_0, ref __self_1), &Closure(ref __arg_1_0, ref __arg_1_1)) => {
+                    __self_0 == __arg_1_0 && __self_1 == __arg_1_1
+                }
+                (
+                    &Generator(ref __self_0, ref __self_1, ref __self_2),
+                    &Generator(ref __arg_1_0, ref __arg_1_1, ref __arg_1_2),
+                ) => __self_0 == __arg_1_0 && __self_1 == __arg_1_1 && __self_2 == __arg_1_2,
+                (&GeneratorWitness(ref __self_0), &GeneratorWitness(ref __arg_1_0)) => {
+                    __self_0 == __arg_1_0
+                }
+                (&Tuple(ref __self_0), &Tuple(ref __arg_1_0)) => __self_0 == __arg_1_0,
+                (&Projection(ref __self_0), &Projection(ref __arg_1_0)) => __self_0 == __arg_1_0,
+                (&Opaque(ref __self_0, ref __self_1), &Opaque(ref __arg_1_0, ref __arg_1_1)) => {
+                    __self_0 == __arg_1_0 && __self_1 == __arg_1_1
+                }
+                (&Param(ref __self_0), &Param(ref __arg_1_0)) => __self_0 == __arg_1_0,
+                (&Bound(ref __self_0, ref __self_1), &Bound(ref __arg_1_0, ref __arg_1_1)) => {
+                    __self_0 == __arg_1_0 && __self_1 == __arg_1_1
+                }
+                (&Placeholder(ref __self_0), &Placeholder(ref __arg_1_0)) => __self_0 == __arg_1_0,
+                (&Infer(ref __self_0), &Infer(ref __arg_1_0)) => __self_0 == __arg_1_0,
+                (&Error(ref __self_0), &Error(ref __arg_1_0)) => __self_0 == __arg_1_0,
+                _ => true,
+            }
+        } else {
+            false
+        }
+    }
+}
+
+// This is manually implemented because a derive would require `I: Eq`
+impl<I: Interner> Eq for TyKind<I> {}
+
+// This is manually implemented because a derive would require `I: PartialOrd`
+impl<I: Interner> PartialOrd for TyKind<I> {
+    #[inline]
+    fn partial_cmp(&self, other: &TyKind<I>) -> Option<Ordering> {
+        Some(Ord::cmp(self, other))
+    }
+}
+
+// This is manually implemented because a derive would require `I: Ord`
+impl<I: Interner> Ord for TyKind<I> {
+    #[inline]
+    fn cmp(&self, other: &TyKind<I>) -> Ordering {
+        let __self_vi = tykind_discriminant(self);
+        let __arg_1_vi = tykind_discriminant(other);
+        if __self_vi == __arg_1_vi {
+            match (&*self, &*other) {
+                (&Int(ref __self_0), &Int(ref __arg_1_0)) => Ord::cmp(__self_0, __arg_1_0),
+                (&Uint(ref __self_0), &Uint(ref __arg_1_0)) => Ord::cmp(__self_0, __arg_1_0),
+                (&Float(ref __self_0), &Float(ref __arg_1_0)) => Ord::cmp(__self_0, __arg_1_0),
+                (&Adt(ref __self_0, ref __self_1), &Adt(ref __arg_1_0, ref __arg_1_1)) => {
+                    match Ord::cmp(__self_0, __arg_1_0) {
+                        Ordering::Equal => Ord::cmp(__self_1, __arg_1_1),
+                        cmp => cmp,
+                    }
+                }
+                (&Foreign(ref __self_0), &Foreign(ref __arg_1_0)) => Ord::cmp(__self_0, __arg_1_0),
+                (&Array(ref __self_0, ref __self_1), &Array(ref __arg_1_0, ref __arg_1_1)) => {
+                    match Ord::cmp(__self_0, __arg_1_0) {
+                        Ordering::Equal => Ord::cmp(__self_1, __arg_1_1),
+                        cmp => cmp,
+                    }
+                }
+                (&Slice(ref __self_0), &Slice(ref __arg_1_0)) => Ord::cmp(__self_0, __arg_1_0),
+                (&RawPtr(ref __self_0), &RawPtr(ref __arg_1_0)) => Ord::cmp(__self_0, __arg_1_0),
+                (
+                    &Ref(ref __self_0, ref __self_1, ref __self_2),
+                    &Ref(ref __arg_1_0, ref __arg_1_1, ref __arg_1_2),
+                ) => match Ord::cmp(__self_0, __arg_1_0) {
+                    Ordering::Equal => match Ord::cmp(__self_1, __arg_1_1) {
+                        Ordering::Equal => Ord::cmp(__self_2, __arg_1_2),
+                        cmp => cmp,
+                    },
+                    cmp => cmp,
+                },
+                (&FnDef(ref __self_0, ref __self_1), &FnDef(ref __arg_1_0, ref __arg_1_1)) => {
+                    match Ord::cmp(__self_0, __arg_1_0) {
+                        Ordering::Equal => Ord::cmp(__self_1, __arg_1_1),
+                        cmp => cmp,
+                    }
+                }
+                (&FnPtr(ref __self_0), &FnPtr(ref __arg_1_0)) => Ord::cmp(__self_0, __arg_1_0),
+                (&Dynamic(ref __self_0, ref __self_1), &Dynamic(ref __arg_1_0, ref __arg_1_1)) => {
+                    match Ord::cmp(__self_0, __arg_1_0) {
+                        Ordering::Equal => Ord::cmp(__self_1, __arg_1_1),
+                        cmp => cmp,
+                    }
+                }
+                (&Closure(ref __self_0, ref __self_1), &Closure(ref __arg_1_0, ref __arg_1_1)) => {
+                    match Ord::cmp(__self_0, __arg_1_0) {
+                        Ordering::Equal => Ord::cmp(__self_1, __arg_1_1),
+                        cmp => cmp,
+                    }
+                }
+                (
+                    &Generator(ref __self_0, ref __self_1, ref __self_2),
+                    &Generator(ref __arg_1_0, ref __arg_1_1, ref __arg_1_2),
+                ) => match Ord::cmp(__self_0, __arg_1_0) {
+                    Ordering::Equal => match Ord::cmp(__self_1, __arg_1_1) {
+                        Ordering::Equal => Ord::cmp(__self_2, __arg_1_2),
+                        cmp => cmp,
+                    },
+                    cmp => cmp,
+                },
+                (&GeneratorWitness(ref __self_0), &GeneratorWitness(ref __arg_1_0)) => {
+                    Ord::cmp(__self_0, __arg_1_0)
+                }
+                (&Tuple(ref __self_0), &Tuple(ref __arg_1_0)) => Ord::cmp(__self_0, __arg_1_0),
+                (&Projection(ref __self_0), &Projection(ref __arg_1_0)) => {
+                    Ord::cmp(__self_0, __arg_1_0)
+                }
+                (&Opaque(ref __self_0, ref __self_1), &Opaque(ref __arg_1_0, ref __arg_1_1)) => {
+                    match Ord::cmp(__self_0, __arg_1_0) {
+                        Ordering::Equal => Ord::cmp(__self_1, __arg_1_1),
+                        cmp => cmp,
+                    }
+                }
+                (&Param(ref __self_0), &Param(ref __arg_1_0)) => Ord::cmp(__self_0, __arg_1_0),
+                (&Bound(ref __self_0, ref __self_1), &Bound(ref __arg_1_0, ref __arg_1_1)) => {
+                    match Ord::cmp(__self_0, __arg_1_0) {
+                        Ordering::Equal => Ord::cmp(__self_1, __arg_1_1),
+                        cmp => cmp,
+                    }
+                }
+                (&Placeholder(ref __self_0), &Placeholder(ref __arg_1_0)) => {
+                    Ord::cmp(__self_0, __arg_1_0)
+                }
+                (&Infer(ref __self_0), &Infer(ref __arg_1_0)) => Ord::cmp(__self_0, __arg_1_0),
+                (&Error(ref __self_0), &Error(ref __arg_1_0)) => Ord::cmp(__self_0, __arg_1_0),
+                _ => Ordering::Equal,
+            }
+        } else {
+            Ord::cmp(&__self_vi, &__arg_1_vi)
+        }
+    }
+}
+
+// This is manually implemented because a derive would require `I: Hash`
+impl<I: Interner> hash::Hash for TyKind<I> {
+    fn hash<__H: hash::Hasher>(&self, state: &mut __H) -> () {
+        match (&*self,) {
+            (&Int(ref __self_0),) => {
+                hash::Hash::hash(&tykind_discriminant(self), state);
+                hash::Hash::hash(__self_0, state)
+            }
+            (&Uint(ref __self_0),) => {
+                hash::Hash::hash(&tykind_discriminant(self), state);
+                hash::Hash::hash(__self_0, state)
+            }
+            (&Float(ref __self_0),) => {
+                hash::Hash::hash(&tykind_discriminant(self), state);
+                hash::Hash::hash(__self_0, state)
+            }
+            (&Adt(ref __self_0, ref __self_1),) => {
+                hash::Hash::hash(&tykind_discriminant(self), state);
+                hash::Hash::hash(__self_0, state);
+                hash::Hash::hash(__self_1, state)
+            }
+            (&Foreign(ref __self_0),) => {
+                hash::Hash::hash(&tykind_discriminant(self), state);
+                hash::Hash::hash(__self_0, state)
+            }
+            (&Array(ref __self_0, ref __self_1),) => {
+                hash::Hash::hash(&tykind_discriminant(self), state);
+                hash::Hash::hash(__self_0, state);
+                hash::Hash::hash(__self_1, state)
+            }
+            (&Slice(ref __self_0),) => {
+                hash::Hash::hash(&tykind_discriminant(self), state);
+                hash::Hash::hash(__self_0, state)
+            }
+            (&RawPtr(ref __self_0),) => {
+                hash::Hash::hash(&tykind_discriminant(self), state);
+                hash::Hash::hash(__self_0, state)
+            }
+            (&Ref(ref __self_0, ref __self_1, ref __self_2),) => {
+                hash::Hash::hash(&tykind_discriminant(self), state);
+                hash::Hash::hash(__self_0, state);
+                hash::Hash::hash(__self_1, state);
+                hash::Hash::hash(__self_2, state)
+            }
+            (&FnDef(ref __self_0, ref __self_1),) => {
+                hash::Hash::hash(&tykind_discriminant(self), state);
+                hash::Hash::hash(__self_0, state);
+                hash::Hash::hash(__self_1, state)
+            }
+            (&FnPtr(ref __self_0),) => {
+                hash::Hash::hash(&tykind_discriminant(self), state);
+                hash::Hash::hash(__self_0, state)
+            }
+            (&Dynamic(ref __self_0, ref __self_1),) => {
+                hash::Hash::hash(&tykind_discriminant(self), state);
+                hash::Hash::hash(__self_0, state);
+                hash::Hash::hash(__self_1, state)
+            }
+            (&Closure(ref __self_0, ref __self_1),) => {
+                hash::Hash::hash(&tykind_discriminant(self), state);
+                hash::Hash::hash(__self_0, state);
+                hash::Hash::hash(__self_1, state)
+            }
+            (&Generator(ref __self_0, ref __self_1, ref __self_2),) => {
+                hash::Hash::hash(&tykind_discriminant(self), state);
+                hash::Hash::hash(__self_0, state);
+                hash::Hash::hash(__self_1, state);
+                hash::Hash::hash(__self_2, state)
+            }
+            (&GeneratorWitness(ref __self_0),) => {
+                hash::Hash::hash(&tykind_discriminant(self), state);
+                hash::Hash::hash(__self_0, state)
+            }
+            (&Tuple(ref __self_0),) => {
+                hash::Hash::hash(&tykind_discriminant(self), state);
+                hash::Hash::hash(__self_0, state)
+            }
+            (&Projection(ref __self_0),) => {
+                hash::Hash::hash(&tykind_discriminant(self), state);
+                hash::Hash::hash(__self_0, state)
+            }
+            (&Opaque(ref __self_0, ref __self_1),) => {
+                hash::Hash::hash(&tykind_discriminant(self), state);
+                hash::Hash::hash(__self_0, state);
+                hash::Hash::hash(__self_1, state)
+            }
+            (&Param(ref __self_0),) => {
+                hash::Hash::hash(&tykind_discriminant(self), state);
+                hash::Hash::hash(__self_0, state)
+            }
+            (&Bound(ref __self_0, ref __self_1),) => {
+                hash::Hash::hash(&tykind_discriminant(self), state);
+                hash::Hash::hash(__self_0, state);
+                hash::Hash::hash(__self_1, state)
+            }
+            (&Placeholder(ref __self_0),) => {
+                hash::Hash::hash(&tykind_discriminant(self), state);
+                hash::Hash::hash(__self_0, state)
+            }
+            (&Infer(ref __self_0),) => {
+                hash::Hash::hash(&tykind_discriminant(self), state);
+                hash::Hash::hash(__self_0, state)
+            }
+            (&Error(ref __self_0),) => {
+                hash::Hash::hash(&tykind_discriminant(self), state);
+                hash::Hash::hash(__self_0, state)
+            }
+            _ => hash::Hash::hash(&tykind_discriminant(self), state),
+        }
+    }
+}
+
+// This is manually implemented because a derive would require `I: Debug`
+impl<I: Interner> fmt::Debug for TyKind<I> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match (&*self,) {
+            (&Bool,) => fmt::Formatter::write_str(f, "Bool"),
+            (&Char,) => fmt::Formatter::write_str(f, "Char"),
+            (&Int(ref __self_0),) => {
+                let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Int");
+                let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
+                fmt::DebugTuple::finish(debug_trait_builder)
+            }
+            (&Uint(ref __self_0),) => {
+                let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Uint");
+                let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
+                fmt::DebugTuple::finish(debug_trait_builder)
+            }
+            (&Float(ref __self_0),) => {
+                let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Float");
+                let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
+                fmt::DebugTuple::finish(debug_trait_builder)
+            }
+            (&Adt(ref __self_0, ref __self_1),) => {
+                let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Adt");
+                let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
+                let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_1);
+                fmt::DebugTuple::finish(debug_trait_builder)
+            }
+            (&Foreign(ref __self_0),) => {
+                let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Foreign");
+                let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
+                fmt::DebugTuple::finish(debug_trait_builder)
+            }
+            (&Str,) => fmt::Formatter::write_str(f, "Str"),
+            (&Array(ref __self_0, ref __self_1),) => {
+                let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Array");
+                let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
+                let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_1);
+                fmt::DebugTuple::finish(debug_trait_builder)
+            }
+            (&Slice(ref __self_0),) => {
+                let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Slice");
+                let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
+                fmt::DebugTuple::finish(debug_trait_builder)
+            }
+            (&RawPtr(ref __self_0),) => {
+                let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "RawPtr");
+                let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
+                fmt::DebugTuple::finish(debug_trait_builder)
+            }
+            (&Ref(ref __self_0, ref __self_1, ref __self_2),) => {
+                let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Ref");
+                let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
+                let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_1);
+                let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_2);
+                fmt::DebugTuple::finish(debug_trait_builder)
+            }
+            (&FnDef(ref __self_0, ref __self_1),) => {
+                let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "FnDef");
+                let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
+                let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_1);
+                fmt::DebugTuple::finish(debug_trait_builder)
+            }
+            (&FnPtr(ref __self_0),) => {
+                let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "FnPtr");
+                let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
+                fmt::DebugTuple::finish(debug_trait_builder)
+            }
+            (&Dynamic(ref __self_0, ref __self_1),) => {
+                let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Dynamic");
+                let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
+                let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_1);
+                fmt::DebugTuple::finish(debug_trait_builder)
+            }
+            (&Closure(ref __self_0, ref __self_1),) => {
+                let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Closure");
+                let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
+                let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_1);
+                fmt::DebugTuple::finish(debug_trait_builder)
+            }
+            (&Generator(ref __self_0, ref __self_1, ref __self_2),) => {
+                let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Generator");
+                let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
+                let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_1);
+                let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_2);
+                fmt::DebugTuple::finish(debug_trait_builder)
+            }
+            (&GeneratorWitness(ref __self_0),) => {
+                let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "GeneratorWitness");
+                let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
+                fmt::DebugTuple::finish(debug_trait_builder)
+            }
+            (&Never,) => fmt::Formatter::write_str(f, "Never"),
+            (&Tuple(ref __self_0),) => {
+                let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Tuple");
+                let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
+                fmt::DebugTuple::finish(debug_trait_builder)
+            }
+            (&Projection(ref __self_0),) => {
+                let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Projection");
+                let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
+                fmt::DebugTuple::finish(debug_trait_builder)
+            }
+            (&Opaque(ref __self_0, ref __self_1),) => {
+                let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Opaque");
+                let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
+                let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_1);
+                fmt::DebugTuple::finish(debug_trait_builder)
+            }
+            (&Param(ref __self_0),) => {
+                let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Param");
+                let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
+                fmt::DebugTuple::finish(debug_trait_builder)
+            }
+            (&Bound(ref __self_0, ref __self_1),) => {
+                let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Bound");
+                let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
+                let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_1);
+                fmt::DebugTuple::finish(debug_trait_builder)
+            }
+            (&Placeholder(ref __self_0),) => {
+                let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Placeholder");
+                let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
+                fmt::DebugTuple::finish(debug_trait_builder)
+            }
+            (&Infer(ref __self_0),) => {
+                let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Infer");
+                let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
+                fmt::DebugTuple::finish(debug_trait_builder)
+            }
+            (&Error(ref __self_0),) => {
+                let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Error");
+                let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
+                fmt::DebugTuple::finish(debug_trait_builder)
+            }
+        }
+    }
+}
+
+// This is manually implemented because a derive would require `I: Encodable`
+impl<I: Interner, E: TyEncoder> Encodable<E> for TyKind<I>
+where
+    I::DelaySpanBugEmitted: Encodable<E>,
+    I::AdtDef: Encodable<E>,
+    I::SubstsRef: Encodable<E>,
+    I::DefId: Encodable<E>,
+    I::Ty: Encodable<E>,
+    I::Const: Encodable<E>,
+    I::Region: Encodable<E>,
+    I::TypeAndMut: Encodable<E>,
+    I::Mutability: Encodable<E>,
+    I::Movability: Encodable<E>,
+    I::PolyFnSig: Encodable<E>,
+    I::ListBinderExistentialPredicate: Encodable<E>,
+    I::BinderListTy: Encodable<E>,
+    I::ListTy: Encodable<E>,
+    I::ProjectionTy: Encodable<E>,
+    I::ParamTy: Encodable<E>,
+    I::BoundTy: Encodable<E>,
+    I::PlaceholderType: Encodable<E>,
+    I::InferTy: Encodable<E>,
+    I::DelaySpanBugEmitted: Encodable<E>,
+    I::PredicateKind: Encodable<E>,
+    I::AllocId: Encodable<E>,
+{
+    fn encode(&self, e: &mut E) {
+        let disc = tykind_discriminant(self);
+        match self {
+            Bool => e.emit_enum_variant(disc, |_| {}),
+            Char => e.emit_enum_variant(disc, |_| {}),
+            Int(i) => e.emit_enum_variant(disc, |e| {
+                i.encode(e);
+            }),
+            Uint(u) => e.emit_enum_variant(disc, |e| {
+                u.encode(e);
+            }),
+            Float(f) => e.emit_enum_variant(disc, |e| {
+                f.encode(e);
+            }),
+            Adt(adt, substs) => e.emit_enum_variant(disc, |e| {
+                adt.encode(e);
+                substs.encode(e);
+            }),
+            Foreign(def_id) => e.emit_enum_variant(disc, |e| {
+                def_id.encode(e);
+            }),
+            Str => e.emit_enum_variant(disc, |_| {}),
+            Array(t, c) => e.emit_enum_variant(disc, |e| {
+                t.encode(e);
+                c.encode(e);
+            }),
+            Slice(t) => e.emit_enum_variant(disc, |e| {
+                t.encode(e);
+            }),
+            RawPtr(tam) => e.emit_enum_variant(disc, |e| {
+                tam.encode(e);
+            }),
+            Ref(r, t, m) => e.emit_enum_variant(disc, |e| {
+                r.encode(e);
+                t.encode(e);
+                m.encode(e);
+            }),
+            FnDef(def_id, substs) => e.emit_enum_variant(disc, |e| {
+                def_id.encode(e);
+                substs.encode(e);
+            }),
+            FnPtr(polyfnsig) => e.emit_enum_variant(disc, |e| {
+                polyfnsig.encode(e);
+            }),
+            Dynamic(l, r) => e.emit_enum_variant(disc, |e| {
+                l.encode(e);
+                r.encode(e);
+            }),
+            Closure(def_id, substs) => e.emit_enum_variant(disc, |e| {
+                def_id.encode(e);
+                substs.encode(e);
+            }),
+            Generator(def_id, substs, m) => e.emit_enum_variant(disc, |e| {
+                def_id.encode(e);
+                substs.encode(e);
+                m.encode(e);
+            }),
+            GeneratorWitness(b) => e.emit_enum_variant(disc, |e| {
+                b.encode(e);
+            }),
+            Never => e.emit_enum_variant(disc, |_| {}),
+            Tuple(substs) => e.emit_enum_variant(disc, |e| {
+                substs.encode(e);
+            }),
+            Projection(p) => e.emit_enum_variant(disc, |e| {
+                p.encode(e);
+            }),
+            Opaque(def_id, substs) => e.emit_enum_variant(disc, |e| {
+                def_id.encode(e);
+                substs.encode(e);
+            }),
+            Param(p) => e.emit_enum_variant(disc, |e| {
+                p.encode(e);
+            }),
+            Bound(d, b) => e.emit_enum_variant(disc, |e| {
+                d.encode(e);
+                b.encode(e);
+            }),
+            Placeholder(p) => e.emit_enum_variant(disc, |e| {
+                p.encode(e);
+            }),
+            Infer(i) => e.emit_enum_variant(disc, |e| {
+                i.encode(e);
+            }),
+            Error(d) => e.emit_enum_variant(disc, |e| {
+                d.encode(e);
+            }),
+        }
+    }
+}
+
+// This is manually implemented because a derive would require `I: Decodable`
+impl<I: Interner, D: TyDecoder<I = I>> Decodable<D> for TyKind<I>
+where
+    I::DelaySpanBugEmitted: Decodable<D>,
+    I::AdtDef: Decodable<D>,
+    I::SubstsRef: Decodable<D>,
+    I::DefId: Decodable<D>,
+    I::Ty: Decodable<D>,
+    I::Const: Decodable<D>,
+    I::Region: Decodable<D>,
+    I::TypeAndMut: Decodable<D>,
+    I::Mutability: Decodable<D>,
+    I::Movability: Decodable<D>,
+    I::PolyFnSig: Decodable<D>,
+    I::ListBinderExistentialPredicate: Decodable<D>,
+    I::BinderListTy: Decodable<D>,
+    I::ListTy: Decodable<D>,
+    I::ProjectionTy: Decodable<D>,
+    I::ParamTy: Decodable<D>,
+    I::BoundTy: Decodable<D>,
+    I::PlaceholderType: Decodable<D>,
+    I::InferTy: Decodable<D>,
+    I::DelaySpanBugEmitted: Decodable<D>,
+    I::PredicateKind: Decodable<D>,
+    I::AllocId: Decodable<D>,
+{
+    fn decode(d: &mut D) -> Self {
+        match Decoder::read_usize(d) {
+            0 => Bool,
+            1 => Char,
+            2 => Int(Decodable::decode(d)),
+            3 => Uint(Decodable::decode(d)),
+            4 => Float(Decodable::decode(d)),
+            5 => Adt(Decodable::decode(d), Decodable::decode(d)),
+            6 => Foreign(Decodable::decode(d)),
+            7 => Str,
+            8 => Array(Decodable::decode(d), Decodable::decode(d)),
+            9 => Slice(Decodable::decode(d)),
+            10 => RawPtr(Decodable::decode(d)),
+            11 => Ref(Decodable::decode(d), Decodable::decode(d), Decodable::decode(d)),
+            12 => FnDef(Decodable::decode(d), Decodable::decode(d)),
+            13 => FnPtr(Decodable::decode(d)),
+            14 => Dynamic(Decodable::decode(d), Decodable::decode(d)),
+            15 => Closure(Decodable::decode(d), Decodable::decode(d)),
+            16 => Generator(Decodable::decode(d), Decodable::decode(d), Decodable::decode(d)),
+            17 => GeneratorWitness(Decodable::decode(d)),
+            18 => Never,
+            19 => Tuple(Decodable::decode(d)),
+            20 => Projection(Decodable::decode(d)),
+            21 => Opaque(Decodable::decode(d), Decodable::decode(d)),
+            22 => Param(Decodable::decode(d)),
+            23 => Bound(Decodable::decode(d), Decodable::decode(d)),
+            24 => Placeholder(Decodable::decode(d)),
+            25 => Infer(Decodable::decode(d)),
+            26 => Error(Decodable::decode(d)),
+            _ => panic!(
+                "{}",
+                format!(
+                    "invalid enum variant tag while decoding `{}`, expected 0..{}",
+                    "TyKind", 27,
+                )
+            ),
+        }
+    }
+}
+
+// This is not a derived impl because a derive would require `I: HashStable`
+#[allow(rustc::usage_of_ty_tykind)]
+impl<CTX, I: Interner> HashStable<CTX> for TyKind<I>
+where
+    I::AdtDef: HashStable<CTX>,
+    I::DefId: HashStable<CTX>,
+    I::SubstsRef: HashStable<CTX>,
+    I::Ty: HashStable<CTX>,
+    I::Const: HashStable<CTX>,
+    I::TypeAndMut: HashStable<CTX>,
+    I::PolyFnSig: HashStable<CTX>,
+    I::ListBinderExistentialPredicate: HashStable<CTX>,
+    I::Region: HashStable<CTX>,
+    I::Movability: HashStable<CTX>,
+    I::Mutability: HashStable<CTX>,
+    I::BinderListTy: HashStable<CTX>,
+    I::ListTy: HashStable<CTX>,
+    I::ProjectionTy: HashStable<CTX>,
+    I::BoundTy: HashStable<CTX>,
+    I::ParamTy: HashStable<CTX>,
+    I::PlaceholderType: HashStable<CTX>,
+    I::InferTy: HashStable<CTX>,
+    I::DelaySpanBugEmitted: HashStable<CTX>,
+{
+    #[inline]
+    fn hash_stable(
+        &self,
+        __hcx: &mut CTX,
+        __hasher: &mut rustc_data_structures::stable_hasher::StableHasher,
+    ) {
+        std::mem::discriminant(self).hash_stable(__hcx, __hasher);
+        match self {
+            Bool => {}
+            Char => {}
+            Int(i) => {
+                i.hash_stable(__hcx, __hasher);
+            }
+            Uint(u) => {
+                u.hash_stable(__hcx, __hasher);
+            }
+            Float(f) => {
+                f.hash_stable(__hcx, __hasher);
+            }
+            Adt(adt, substs) => {
+                adt.hash_stable(__hcx, __hasher);
+                substs.hash_stable(__hcx, __hasher);
+            }
+            Foreign(def_id) => {
+                def_id.hash_stable(__hcx, __hasher);
+            }
+            Str => {}
+            Array(t, c) => {
+                t.hash_stable(__hcx, __hasher);
+                c.hash_stable(__hcx, __hasher);
+            }
+            Slice(t) => {
+                t.hash_stable(__hcx, __hasher);
+            }
+            RawPtr(tam) => {
+                tam.hash_stable(__hcx, __hasher);
+            }
+            Ref(r, t, m) => {
+                r.hash_stable(__hcx, __hasher);
+                t.hash_stable(__hcx, __hasher);
+                m.hash_stable(__hcx, __hasher);
+            }
+            FnDef(def_id, substs) => {
+                def_id.hash_stable(__hcx, __hasher);
+                substs.hash_stable(__hcx, __hasher);
+            }
+            FnPtr(polyfnsig) => {
+                polyfnsig.hash_stable(__hcx, __hasher);
+            }
+            Dynamic(l, r) => {
+                l.hash_stable(__hcx, __hasher);
+                r.hash_stable(__hcx, __hasher);
+            }
+            Closure(def_id, substs) => {
+                def_id.hash_stable(__hcx, __hasher);
+                substs.hash_stable(__hcx, __hasher);
+            }
+            Generator(def_id, substs, m) => {
+                def_id.hash_stable(__hcx, __hasher);
+                substs.hash_stable(__hcx, __hasher);
+                m.hash_stable(__hcx, __hasher);
+            }
+            GeneratorWitness(b) => {
+                b.hash_stable(__hcx, __hasher);
+            }
+            Never => {}
+            Tuple(substs) => {
+                substs.hash_stable(__hcx, __hasher);
+            }
+            Projection(p) => {
+                p.hash_stable(__hcx, __hasher);
+            }
+            Opaque(def_id, substs) => {
+                def_id.hash_stable(__hcx, __hasher);
+                substs.hash_stable(__hcx, __hasher);
+            }
+            Param(p) => {
+                p.hash_stable(__hcx, __hasher);
+            }
+            Bound(d, b) => {
+                d.hash_stable(__hcx, __hasher);
+                b.hash_stable(__hcx, __hasher);
+            }
+            Placeholder(p) => {
+                p.hash_stable(__hcx, __hasher);
+            }
+            Infer(i) => {
+                i.hash_stable(__hcx, __hasher);
+            }
+            Error(d) => {
+                d.hash_stable(__hcx, __hasher);
+            }
+        }
+    }
+}
+
+/// 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_const_eval::borrow_check`
+/// module for more information.
+///
+/// Note: operations are on the wrapper `Region` type, which is interned,
+/// rather than this type.
+///
+/// ## The Region lattice within a given function
+///
+/// In general, the region lattice looks like
+///
+/// ```text
+/// static ----------+-----...------+       (greatest)
+/// |                |              |
+/// early-bound and  |              |
+/// free regions     |              |
+/// |                |              |
+/// |                |              |
+/// empty(root)   placeholder(U1)   |
+/// |            /                  |
+/// |           /         placeholder(Un)
+/// empty(U1) --         /
+/// |                   /
+/// ...                /
+/// |                 /
+/// empty(Un) --------                      (smallest)
+/// ```
+///
+/// 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.
+///
+/// Note that inference variables and bound regions are not included
+/// in this diagram. In the case of inference variables, they should
+/// be inferred to some other region from the diagram.  In the case of
+/// bound regions, they are excluded because they don't make sense to
+/// include -- the diagram indicates the relationship between free
+/// regions.
+///
+/// ## Inference variables
+///
+/// During region inference, we sometimes create inference variables,
+/// represented as `ReVar`. These will be inferred by the code in
+/// `infer::lexical_region_resolve` to some free region from the
+/// lattice above (the minimal region that meets the
+/// constraints).
+///
+/// During NLL checking, where regions are defined differently, we
+/// also use `ReVar` -- in that case, the index is used to index into
+/// the NLL region checker's data structures. The variable may in fact
+/// represent either a free region or an inference variable, in that
+/// case.
+///
+/// ## Bound Regions
+///
+/// These are regions that are stored behind a binder and must be substituted
+/// with some concrete region before being used. There are two kind of
+/// bound regions: early-bound, which are bound in an item's `Generics`,
+/// and are substituted by an `InternalSubsts`, and late-bound, which are part of
+/// higher-ranked types (e.g., `for<'a> fn(&'a ())`), and are substituted by
+/// the likes of `liberate_late_bound_regions`. The distinction exists
+/// because higher-ranked lifetimes aren't supported in all places. See [1][2].
+///
+/// Unlike `Param`s, bound regions are not supposed to exist "in the wild"
+/// outside their binder, e.g., in types passed to type inference, and
+/// should first be substituted (by placeholder regions, free regions,
+/// or region variables).
+///
+/// ## Placeholder and Free Regions
+///
+/// One often wants to work with bound regions without knowing their precise
+/// identity. For example, when checking a function, the lifetime of a borrow
+/// can end up being assigned to some region parameter. In these cases,
+/// it must be ensured that bounds on the region can't be accidentally
+/// assumed without being checked.
+///
+/// To do this, we replace the bound regions with placeholder markers,
+/// which don't satisfy any relation not explicitly provided.
+///
+/// There are two kinds of placeholder regions in rustc: `ReFree` and
+/// `RePlaceholder`. When checking an item's body, `ReFree` is supposed
+/// to be used. These also support explicit bounds: both the internally-stored
+/// *scope*, which the region is assumed to outlive, as well as other
+/// relations stored in the `FreeRegionMap`. Note that these relations
+/// aren't checked when you `make_subregion` (or `eq_types`), only by
+/// `resolve_regions_and_report_errors`.
+///
+/// When working with higher-ranked types, some region relations aren't
+/// yet known, so you can't just call `resolve_regions_and_report_errors`.
+/// `RePlaceholder` is designed for this purpose. In these contexts,
+/// there's also the risk that some inference variable laying around will
+/// get unified with your placeholder region: if you want to check whether
+/// `for<'a> Foo<'_>: 'a`, and you substitute your bound region `'a`
+/// with a placeholder region `'%a`, the variable `'_` would just be
+/// instantiated to the placeholder region `'%a`, which is wrong because
+/// the inference variable is supposed to satisfy the relation
+/// *for every value of the placeholder region*. To ensure that doesn't
+/// happen, you can use `leak_check`. This is more clearly explained
+/// by the [rustc dev guide].
+///
+/// [1]: https://smallcultfollowing.com/babysteps/blog/2013/10/29/intermingled-parameter-lists/
+/// [2]: https://smallcultfollowing.com/babysteps/blog/2013/11/04/intermingled-parameter-lists/
+/// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/hrtb.html
+pub enum RegionKind<I: Interner> {
+    /// Region bound in a type or fn declaration which will be
+    /// substituted 'early' -- that is, at the same time when type
+    /// parameters are substituted.
+    ReEarlyBound(I::EarlyBoundRegion),
+
+    /// Region bound in a function scope, which will be substituted when the
+    /// function is called.
+    ReLateBound(DebruijnIndex, I::BoundRegion),
+
+    /// When checking a function body, the types of all arguments and so forth
+    /// that refer to bound region parameters are modified to refer to free
+    /// region parameters.
+    ReFree(I::FreeRegion),
+
+    /// Static data that has an "infinite" lifetime. Top in the region lattice.
+    ReStatic,
+
+    /// A region variable. Should not exist outside of type inference.
+    ReVar(I::RegionVid),
+
+    /// A placeholder region -- basically, the higher-ranked version of `ReFree`.
+    /// Should not exist outside of type inference.
+    RePlaceholder(I::PlaceholderRegion),
+
+    /// Empty lifetime is for data that is never accessed.  We tag the
+    /// empty lifetime with a universe -- the idea is that we don't
+    /// want `exists<'a> { forall<'b> { 'b: 'a } }` to be satisfiable.
+    /// Therefore, the `'empty` in a universe `U` is less than all
+    /// regions visible from `U`, but not less than regions not visible
+    /// from `U`.
+    ReEmpty(UniverseIndex),
+
+    /// Erased region, used by trait selection, in MIR and during codegen.
+    ReErased,
+}
+
+// This is manually implemented for `RegionKind` because `std::mem::discriminant`
+// returns an opaque value that is `PartialEq` but not `PartialOrd`
+#[inline]
+const fn regionkind_discriminant<I: Interner>(value: &RegionKind<I>) -> usize {
+    match value {
+        ReEarlyBound(_) => 0,
+        ReLateBound(_, _) => 1,
+        ReFree(_) => 2,
+        ReStatic => 3,
+        ReVar(_) => 4,
+        RePlaceholder(_) => 5,
+        ReEmpty(_) => 6,
+        ReErased => 7,
+    }
+}
+
+// This is manually implemented because a derive would require `I: Copy`
+impl<I: Interner> Copy for RegionKind<I>
+where
+    I::EarlyBoundRegion: Copy,
+    I::BoundRegion: Copy,
+    I::FreeRegion: Copy,
+    I::RegionVid: Copy,
+    I::PlaceholderRegion: Copy,
+{
+}
+
+// This is manually implemented because a derive would require `I: Clone`
+impl<I: Interner> Clone for RegionKind<I> {
+    fn clone(&self) -> Self {
+        match self {
+            ReEarlyBound(a) => ReEarlyBound(a.clone()),
+            ReLateBound(a, b) => ReLateBound(a.clone(), b.clone()),
+            ReFree(a) => ReFree(a.clone()),
+            ReStatic => ReStatic,
+            ReVar(a) => ReVar(a.clone()),
+            RePlaceholder(a) => RePlaceholder(a.clone()),
+            ReEmpty(a) => ReEmpty(a.clone()),
+            ReErased => ReErased,
+        }
+    }
+}
+
+// This is manually implemented because a derive would require `I: PartialEq`
+impl<I: Interner> PartialEq for RegionKind<I> {
+    #[inline]
+    fn eq(&self, other: &RegionKind<I>) -> bool {
+        let __self_vi = regionkind_discriminant(self);
+        let __arg_1_vi = regionkind_discriminant(other);
+        if __self_vi == __arg_1_vi {
+            match (&*self, &*other) {
+                (&ReEarlyBound(ref __self_0), &ReEarlyBound(ref __arg_1_0)) => {
+                    __self_0 == __arg_1_0
+                }
+                (
+                    &ReLateBound(ref __self_0, ref __self_1),
+                    &ReLateBound(ref __arg_1_0, ref __arg_1_1),
+                ) => __self_0 == __arg_1_0 && __self_1 == __arg_1_1,
+                (&ReFree(ref __self_0), &ReFree(ref __arg_1_0)) => __self_0 == __arg_1_0,
+                (&ReStatic, &ReStatic) => true,
+                (&ReVar(ref __self_0), &ReVar(ref __arg_1_0)) => __self_0 == __arg_1_0,
+                (&RePlaceholder(ref __self_0), &RePlaceholder(ref __arg_1_0)) => {
+                    __self_0 == __arg_1_0
+                }
+                (&ReEmpty(ref __self_0), &ReEmpty(ref __arg_1_0)) => __self_0 == __arg_1_0,
+                (&ReErased, &ReErased) => true,
+                _ => true,
+            }
+        } else {
+            false
+        }
+    }
+}
+
+// This is manually implemented because a derive would require `I: Eq`
+impl<I: Interner> Eq for RegionKind<I> {}
+
+// This is manually implemented because a derive would require `I: PartialOrd`
+impl<I: Interner> PartialOrd for RegionKind<I> {
+    #[inline]
+    fn partial_cmp(&self, other: &RegionKind<I>) -> Option<Ordering> {
+        Some(Ord::cmp(self, other))
+    }
+}
+
+// This is manually implemented because a derive would require `I: Ord`
+impl<I: Interner> Ord for RegionKind<I> {
+    #[inline]
+    fn cmp(&self, other: &RegionKind<I>) -> Ordering {
+        let __self_vi = regionkind_discriminant(self);
+        let __arg_1_vi = regionkind_discriminant(other);
+        if __self_vi == __arg_1_vi {
+            match (&*self, &*other) {
+                (&ReEarlyBound(ref __self_0), &ReEarlyBound(ref __arg_1_0)) => {
+                    Ord::cmp(__self_0, __arg_1_0)
+                }
+                (
+                    &ReLateBound(ref __self_0, ref __self_1),
+                    &ReLateBound(ref __arg_1_0, ref __arg_1_1),
+                ) => match Ord::cmp(__self_0, __arg_1_0) {
+                    Ordering::Equal => Ord::cmp(__self_1, __arg_1_1),
+                    cmp => cmp,
+                },
+                (&ReFree(ref __self_0), &ReFree(ref __arg_1_0)) => Ord::cmp(__self_0, __arg_1_0),
+                (&ReStatic, &ReStatic) => Ordering::Equal,
+                (&ReVar(ref __self_0), &ReVar(ref __arg_1_0)) => Ord::cmp(__self_0, __arg_1_0),
+                (&RePlaceholder(ref __self_0), &RePlaceholder(ref __arg_1_0)) => {
+                    Ord::cmp(__self_0, __arg_1_0)
+                }
+                (&ReEmpty(ref __self_0), &ReEmpty(ref __arg_1_0)) => Ord::cmp(__self_0, __arg_1_0),
+                (&ReErased, &ReErased) => Ordering::Equal,
+                _ => Ordering::Equal,
+            }
+        } else {
+            Ord::cmp(&__self_vi, &__arg_1_vi)
+        }
+    }
+}
+
+// This is manually implemented because a derive would require `I: Hash`
+impl<I: Interner> hash::Hash for RegionKind<I> {
+    fn hash<__H: hash::Hasher>(&self, state: &mut __H) -> () {
+        match (&*self,) {
+            (&ReEarlyBound(ref __self_0),) => {
+                hash::Hash::hash(&regionkind_discriminant(self), state);
+                hash::Hash::hash(__self_0, state)
+            }
+            (&ReLateBound(ref __self_0, ref __self_1),) => {
+                hash::Hash::hash(&regionkind_discriminant(self), state);
+                hash::Hash::hash(__self_0, state);
+                hash::Hash::hash(__self_1, state)
+            }
+            (&ReFree(ref __self_0),) => {
+                hash::Hash::hash(&regionkind_discriminant(self), state);
+                hash::Hash::hash(__self_0, state)
+            }
+            (&ReStatic,) => {
+                hash::Hash::hash(&regionkind_discriminant(self), state);
+            }
+            (&ReVar(ref __self_0),) => {
+                hash::Hash::hash(&regionkind_discriminant(self), state);
+                hash::Hash::hash(__self_0, state)
+            }
+            (&RePlaceholder(ref __self_0),) => {
+                hash::Hash::hash(&regionkind_discriminant(self), state);
+                hash::Hash::hash(__self_0, state)
+            }
+            (&ReEmpty(ref __self_0),) => {
+                hash::Hash::hash(&regionkind_discriminant(self), state);
+                hash::Hash::hash(__self_0, state)
+            }
+            (&ReErased,) => {
+                hash::Hash::hash(&regionkind_discriminant(self), state);
+            }
+        }
+    }
+}
+
+// This is manually implemented because a derive would require `I: Debug`
+impl<I: Interner> fmt::Debug for RegionKind<I> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            ReEarlyBound(ref data) => write!(f, "ReEarlyBound({:?})", data),
+
+            ReLateBound(binder_id, ref bound_region) => {
+                write!(f, "ReLateBound({:?}, {:?})", binder_id, bound_region)
+            }
+
+            ReFree(ref fr) => fr.fmt(f),
+
+            ReStatic => write!(f, "ReStatic"),
+
+            ReVar(ref vid) => vid.fmt(f),
+
+            RePlaceholder(placeholder) => write!(f, "RePlaceholder({:?})", placeholder),
+
+            ReEmpty(ui) => write!(f, "ReEmpty({:?})", ui),
+
+            ReErased => write!(f, "ReErased"),
+        }
+    }
+}
+
+// This is manually implemented because a derive would require `I: Encodable`
+impl<I: Interner, E: TyEncoder> Encodable<E> for RegionKind<I>
+where
+    I::EarlyBoundRegion: Encodable<E>,
+    I::BoundRegion: Encodable<E>,
+    I::FreeRegion: Encodable<E>,
+    I::RegionVid: Encodable<E>,
+    I::PlaceholderRegion: Encodable<E>,
+{
+    fn encode(&self, e: &mut E) {
+        let disc = regionkind_discriminant(self);
+        match self {
+            ReEarlyBound(a) => e.emit_enum_variant(disc, |e| {
+                a.encode(e);
+            }),
+            ReLateBound(a, b) => e.emit_enum_variant(disc, |e| {
+                a.encode(e);
+                b.encode(e);
+            }),
+            ReFree(a) => e.emit_enum_variant(disc, |e| {
+                a.encode(e);
+            }),
+            ReStatic => e.emit_enum_variant(disc, |_| {}),
+            ReVar(a) => e.emit_enum_variant(disc, |e| {
+                a.encode(e);
+            }),
+            RePlaceholder(a) => e.emit_enum_variant(disc, |e| {
+                a.encode(e);
+            }),
+            ReEmpty(a) => e.emit_enum_variant(disc, |e| {
+                a.encode(e);
+            }),
+            ReErased => e.emit_enum_variant(disc, |_| {}),
+        }
+    }
+}
+
+// This is manually implemented because a derive would require `I: Decodable`
+impl<I: Interner, D: TyDecoder<I = I>> Decodable<D> for RegionKind<I>
+where
+    I::EarlyBoundRegion: Decodable<D>,
+    I::BoundRegion: Decodable<D>,
+    I::FreeRegion: Decodable<D>,
+    I::RegionVid: Decodable<D>,
+    I::PlaceholderRegion: Decodable<D>,
+{
+    fn decode(d: &mut D) -> Self {
+        match Decoder::read_usize(d) {
+            0 => ReEarlyBound(Decodable::decode(d)),
+            1 => ReLateBound(Decodable::decode(d), Decodable::decode(d)),
+            2 => ReFree(Decodable::decode(d)),
+            3 => ReStatic,
+            4 => ReVar(Decodable::decode(d)),
+            5 => RePlaceholder(Decodable::decode(d)),
+            6 => ReEmpty(Decodable::decode(d)),
+            7 => ReErased,
+            _ => panic!(
+                "{}",
+                format!(
+                    "invalid enum variant tag while decoding `{}`, expected 0..{}",
+                    "RegionKind", 8,
+                )
+            ),
+        }
+    }
+}
+
+// This is not a derived impl because a derive would require `I: HashStable`
+impl<CTX, I: Interner> HashStable<CTX> for RegionKind<I>
+where
+    I::EarlyBoundRegion: HashStable<CTX>,
+    I::BoundRegion: HashStable<CTX>,
+    I::FreeRegion: HashStable<CTX>,
+    I::RegionVid: HashStable<CTX>,
+    I::PlaceholderRegion: HashStable<CTX>,
+{
+    #[inline]
+    fn hash_stable(
+        &self,
+        hcx: &mut CTX,
+        hasher: &mut rustc_data_structures::stable_hasher::StableHasher,
+    ) {
+        std::mem::discriminant(self).hash_stable(hcx, hasher);
+        match self {
+            ReErased | ReStatic => {
+                // No variant fields to hash for these ...
+            }
+            ReEmpty(universe) => {
+                universe.hash_stable(hcx, hasher);
+            }
+            ReLateBound(db, br) => {
+                db.hash_stable(hcx, hasher);
+                br.hash_stable(hcx, hasher);
+            }
+            ReEarlyBound(eb) => {
+                eb.hash_stable(hcx, hasher);
+            }
+            ReFree(ref free_region) => {
+                free_region.hash_stable(hcx, hasher);
+            }
+            RePlaceholder(p) => {
+                p.hash_stable(hcx, hasher);
+            }
+            ReVar(reg) => {
+                reg.hash_stable(hcx, hasher);
+            }
+        }
+    }
+}
diff --git a/compiler/rustc_typeck/Cargo.toml b/compiler/rustc_typeck/Cargo.toml
index 57930a2..c08023e 100644
--- a/compiler/rustc_typeck/Cargo.toml
+++ b/compiler/rustc_typeck/Cargo.toml
@@ -29,3 +29,4 @@
 rustc_ty_utils = { path = "../rustc_ty_utils" }
 rustc_lint = { path = "../rustc_lint" }
 rustc_serialize = { path = "../rustc_serialize" }
+rustc_type_ir = { path = "../rustc_type_ir" }
diff --git a/compiler/rustc_typeck/src/astconv/errors.rs b/compiler/rustc_typeck/src/astconv/errors.rs
index 8fe89c6..d111008 100644
--- a/compiler/rustc_typeck/src/astconv/errors.rs
+++ b/compiler/rustc_typeck/src/astconv/errors.rs
@@ -161,7 +161,7 @@
             err.span_suggestion(
                 assoc_name.span,
                 "there is an associated type with a similar name",
-                suggested_name.to_string(),
+                suggested_name,
                 Applicability::MaybeIncorrect,
             );
         } else {
diff --git a/compiler/rustc_typeck/src/astconv/generics.rs b/compiler/rustc_typeck/src/astconv/generics.rs
index dc4bc8f..60682aa 100644
--- a/compiler/rustc_typeck/src/astconv/generics.rs
+++ b/compiler/rustc_typeck/src/astconv/generics.rs
@@ -3,7 +3,7 @@
     AstConv, CreateSubstsForGenericArgsCtxt, ExplicitLateBound, GenericArgCountMismatch,
     GenericArgCountResult, GenericArgPosition,
 };
-use crate::errors::{AssocTypeBindingNotAllowed, ExplicitGenericArgsWithImplTrait};
+use crate::errors::AssocTypeBindingNotAllowed;
 use crate::structured_errors::{GenericArgsInfo, StructuredDiagnostic, WrongNumberOfGenericArgs};
 use rustc_ast::ast::ParamKindOrd;
 use rustc_errors::{struct_span_err, Applicability, Diagnostic, MultiSpan};
@@ -13,7 +13,7 @@
 use rustc_hir::GenericArg;
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_middle::ty::{
-    self, subst, subst::SubstsRef, GenericParamDef, GenericParamDefKind, Ty, TyCtxt,
+    self, subst, subst::SubstsRef, GenericParamDef, GenericParamDefKind, IsSuggestable, Ty, TyCtxt,
 };
 use rustc_session::lint::builtin::LATE_BOUND_LIFETIME_ARGUMENTS;
 use rustc_span::{symbol::kw, Span};
@@ -397,8 +397,6 @@
         is_method_call: IsMethodCall,
     ) -> GenericArgCountResult {
         let empty_args = hir::GenericArgs::none();
-        let suppress_mismatch = Self::check_impl_trait(tcx, seg, generics);
-
         let gen_args = seg.args.unwrap_or(&empty_args);
         let gen_pos = if is_method_call == IsMethodCall::Yes {
             GenericArgPosition::MethodCall
@@ -406,10 +404,17 @@
             GenericArgPosition::Value
         };
         let has_self = generics.parent.is_none() && generics.has_self;
-        let infer_args = seg.infer_args || suppress_mismatch;
 
         Self::check_generic_arg_count(
-            tcx, span, def_id, seg, generics, gen_args, gen_pos, has_self, infer_args,
+            tcx,
+            span,
+            def_id,
+            seg,
+            generics,
+            gen_args,
+            gen_pos,
+            has_self,
+            seg.infer_args,
         )
     }
 
@@ -431,19 +436,14 @@
         let param_counts = gen_params.own_counts();
 
         // Subtracting from param count to ensure type params synthesized from `impl Trait`
-        // cannot be explicitly specified even with `explicit_generic_args_with_impl_trait`
-        // feature enabled.
-        let synth_type_param_count = if tcx.features().explicit_generic_args_with_impl_trait {
-            gen_params
-                .params
-                .iter()
-                .filter(|param| {
-                    matches!(param.kind, ty::GenericParamDefKind::Type { synthetic: true, .. })
-                })
-                .count()
-        } else {
-            0
-        };
+        // cannot be explicitly specified.
+        let synth_type_param_count = gen_params
+            .params
+            .iter()
+            .filter(|param| {
+                matches!(param.kind, ty::GenericParamDefKind::Type { synthetic: true, .. })
+            })
+            .count();
         let named_type_param_count =
             param_counts.types - has_self as usize - synth_type_param_count;
         let infer_lifetimes =
@@ -611,40 +611,6 @@
         }
     }
 
-    /// Report error if there is an explicit type parameter when using `impl Trait`.
-    pub(crate) fn check_impl_trait(
-        tcx: TyCtxt<'_>,
-        seg: &hir::PathSegment<'_>,
-        generics: &ty::Generics,
-    ) -> bool {
-        if seg.infer_args || tcx.features().explicit_generic_args_with_impl_trait {
-            return false;
-        }
-
-        let impl_trait = generics.has_impl_trait();
-
-        if impl_trait {
-            let spans = seg
-                .args()
-                .args
-                .iter()
-                .filter_map(|arg| match arg {
-                    GenericArg::Infer(_) | GenericArg::Type(_) | GenericArg::Const(_) => {
-                        Some(arg.span())
-                    }
-                    _ => None,
-                })
-                .collect::<Vec<_>>();
-
-            tcx.sess.emit_err(ExplicitGenericArgsWithImplTrait {
-                spans,
-                is_nightly_build: tcx.sess.is_nightly_build().then_some(()),
-            });
-        }
-
-        impl_trait
-    }
-
     /// Emits an error regarding forbidden type binding associations
     pub fn prohibit_assoc_ty_binding(tcx: TyCtxt<'_>, span: Span) {
         tcx.sess.emit_err(AssocTypeBindingNotAllowed { span });
diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs
index 2ff32bd..eec3b24 100644
--- a/compiler/rustc_typeck/src/astconv/mod.rs
+++ b/compiler/rustc_typeck/src/astconv/mod.rs
@@ -16,21 +16,24 @@
 use rustc_ast::TraitObjectSyntax;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_errors::{
-    struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, FatalError,
+    struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, FatalError, MultiSpan,
 };
 use rustc_hir as hir;
 use rustc_hir::def::{CtorOf, DefKind, Namespace, Res};
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::intravisit::{walk_generics, Visitor as _};
 use rustc_hir::lang_items::LangItem;
-use rustc_hir::{GenericArg, GenericArgs};
+use rustc_hir::{GenericArg, GenericArgs, OpaqueTyOrigin};
+use rustc_middle::middle::stability::AllowUnstable;
 use rustc_middle::ty::subst::{self, GenericArgKind, InternalSubsts, Subst, SubstsRef};
 use rustc_middle::ty::GenericParamDefKind;
-use rustc_middle::ty::{self, Const, DefIdTree, EarlyBinder, Ty, TyCtxt, TypeFoldable};
+use rustc_middle::ty::{
+    self, Const, DefIdTree, EarlyBinder, IsSuggestable, Ty, TyCtxt, TypeFoldable,
+};
 use rustc_session::lint::builtin::{AMBIGUOUS_ASSOCIATED_ITEMS, BARE_TRAIT_OBJECTS};
 use rustc_span::edition::Edition;
 use rustc_span::lev_distance::find_best_match_for_name;
-use rustc_span::symbol::{Ident, Symbol};
+use rustc_span::symbol::{kw, Ident, Symbol};
 use rustc_span::{Span, DUMMY_SP};
 use rustc_target::spec::abi;
 use rustc_trait_selection::traits;
@@ -426,6 +429,7 @@
                             Some(arg.id()),
                             arg.span(),
                             None,
+                            AllowUnstable::No,
                             |_, _| {
                                 // Default generic parameters may not be marked
                                 // with stability attributes, i.e. when the
@@ -640,7 +644,7 @@
         assoc_bindings
     }
 
-    crate fn create_substs_for_associated_item(
+    pub(crate) fn create_substs_for_associated_item(
         &self,
         tcx: TyCtxt<'tcx>,
         span: Span,
@@ -653,7 +657,7 @@
             span, item_def_id, item_segment
         );
         if tcx.generics_of(item_def_id).params.is_empty() {
-            self.prohibit_generics(slice::from_ref(item_segment));
+            self.prohibit_generics(slice::from_ref(item_segment).iter(), |_| {});
 
             parent_substs
         } else {
@@ -681,7 +685,7 @@
         trait_ref: &hir::TraitRef<'_>,
         self_ty: Ty<'tcx>,
     ) -> ty::TraitRef<'tcx> {
-        self.prohibit_generics(trait_ref.path.segments.split_last().unwrap().1);
+        self.prohibit_generics(trait_ref.path.segments.split_last().unwrap().1.iter(), |_| {});
 
         self.ast_path_to_mono_trait_ref(
             trait_ref.path.span,
@@ -784,7 +788,7 @@
         let args = trait_segment.args();
         let infer_args = trait_segment.infer_args;
 
-        self.prohibit_generics(trait_ref.path.segments.split_last().unwrap().1);
+        self.prohibit_generics(trait_ref.path.segments.split_last().unwrap().1.iter(), |_| {});
         self.complain_about_internal_fn_trait(span, trait_def_id, trait_segment, false);
 
         self.instantiate_poly_trait_ref_inner(
@@ -1575,18 +1579,17 @@
         name: Symbol,
     ) -> ErrorGuaranteed {
         let mut err = struct_span_err!(self.tcx().sess, span, E0223, "ambiguous associated type");
-        if let (true, Ok(snippet)) = (
-            self.tcx()
-                .resolutions(())
-                .confused_type_with_std_module
-                .keys()
-                .any(|full_span| full_span.contains(span)),
-            self.tcx().sess.source_map().span_to_snippet(span),
-        ) {
+        if self
+            .tcx()
+            .resolutions(())
+            .confused_type_with_std_module
+            .keys()
+            .any(|full_span| full_span.contains(span))
+        {
             err.span_suggestion(
-                span,
+                span.shrink_to_lo(),
                 "you are looking for the module in `std`, not the primitive type",
-                format!("std::{}", snippet),
+                "std::",
                 Applicability::MachineApplicable,
             );
         } else {
@@ -1776,12 +1779,17 @@
         hir_ref_id: hir::HirId,
         span: Span,
         qself_ty: Ty<'tcx>,
-        qself_res: Res,
+        qself: &hir::Ty<'_>,
         assoc_segment: &hir::PathSegment<'_>,
         permit_variants: bool,
     ) -> Result<(Ty<'tcx>, DefKind, DefId), ErrorGuaranteed> {
         let tcx = self.tcx();
         let assoc_ident = assoc_segment.ident;
+        let qself_res = if let hir::TyKind::Path(hir::QPath::Resolved(_, ref path)) = qself.kind {
+            path.res
+        } else {
+            Res::Err
+        };
 
         debug!("associated_path_to_ty: {:?}::{}", qself_ty, assoc_ident);
 
@@ -1796,7 +1804,87 @@
                 if let Some(variant_def) = variant_def {
                     if permit_variants {
                         tcx.check_stability(variant_def.def_id, Some(hir_ref_id), span, None);
-                        self.prohibit_generics(slice::from_ref(assoc_segment));
+                        self.prohibit_generics(slice::from_ref(assoc_segment).iter(), |err| {
+                            err.note("enum variants can't have type parameters");
+                            let type_name = tcx.item_name(adt_def.did());
+                            let msg = format!(
+                                "you might have meant to specity type parameters on enum \
+                                 `{type_name}`"
+                            );
+                            let Some(args) = assoc_segment.args else { return; };
+                            // Get the span of the generics args *including* the leading `::`.
+                            let args_span = assoc_segment.ident.span.shrink_to_hi().to(args.span_ext);
+                            if tcx.generics_of(adt_def.did()).count() == 0 {
+                                // FIXME(estebank): we could also verify that the arguments being
+                                // work for the `enum`, instead of just looking if it takes *any*.
+                                err.span_suggestion_verbose(
+                                    args_span,
+                                    &format!("{type_name} doesn't have generic parameters"),
+                                    "",
+                                    Applicability::MachineApplicable,
+                                );
+                                return;
+                            }
+                            let Ok(snippet) = tcx.sess.source_map().span_to_snippet(args_span) else {
+                                err.note(&msg);
+                                return;
+                            };
+                            let (qself_sugg_span, is_self) = if let hir::TyKind::Path(
+                                hir::QPath::Resolved(_, ref path)
+                            ) = qself.kind {
+                                // If the path segment already has type params, we want to overwrite
+                                // them.
+                                match &path.segments[..] {
+                                    // `segment` is the previous to last element on the path,
+                                    // which would normally be the `enum` itself, while the last
+                                    // `_` `PathSegment` corresponds to the variant.
+                                    [.., hir::PathSegment {
+                                        ident,
+                                        args,
+                                        res: Some(Res::Def(DefKind::Enum, _)),
+                                        ..
+                                    }, _] => (
+                                        // We need to include the `::` in `Type::Variant::<Args>`
+                                        // to point the span to `::<Args>`, not just `<Args>`.
+                                        ident.span.shrink_to_hi().to(args.map_or(
+                                            ident.span.shrink_to_hi(),
+                                            |a| a.span_ext)),
+                                        false,
+                                    ),
+                                    [segment] => (
+                                        // We need to include the `::` in `Type::Variant::<Args>`
+                                        // to point the span to `::<Args>`, not just `<Args>`.
+                                        segment.ident.span.shrink_to_hi().to(segment.args.map_or(
+                                            segment.ident.span.shrink_to_hi(),
+                                            |a| a.span_ext)),
+                                        kw::SelfUpper == segment.ident.name,
+                                    ),
+                                    _ => {
+                                        err.note(&msg);
+                                        return;
+                                    }
+                                }
+                            } else {
+                                err.note(&msg);
+                                return;
+                            };
+                            let suggestion = vec![
+                                if is_self {
+                                    // Account for people writing `Self::Variant::<Args>`, where
+                                    // `Self` is the enum, and suggest replacing `Self` with the
+                                    // appropriate type: `Type::<Args>::Variant`.
+                                    (qself.span, format!("{type_name}{snippet}"))
+                                } else {
+                                    (qself_sugg_span, snippet)
+                                },
+                                (args_span, String::new()),
+                            ];
+                            err.multipart_suggestion_verbose(
+                                &msg,
+                                suggestion,
+                                Applicability::MaybeIncorrect,
+                            );
+                        });
                         return Ok((qself_ty, DefKind::Variant, variant_def.def_id));
                     } else {
                         variant_resolution = Some(variant_def.def_id);
@@ -1858,7 +1946,7 @@
                         err.span_suggestion(
                             assoc_ident.span,
                             "there is a variant with a similar name",
-                            suggested_name.to_string(),
+                            suggested_name,
                             Applicability::MaybeIncorrect,
                         );
                     } else {
@@ -2017,69 +2105,113 @@
         self.normalize_ty(span, tcx.mk_projection(item_def_id, item_substs))
     }
 
-    pub fn prohibit_generics<'a, T: IntoIterator<Item = &'a hir::PathSegment<'a>>>(
+    pub fn prohibit_generics<'a>(
         &self,
-        segments: T,
+        segments: impl Iterator<Item = &'a hir::PathSegment<'a>> + Clone,
+        extend: impl Fn(&mut DiagnosticBuilder<'tcx, ErrorGuaranteed>),
     ) -> bool {
-        let mut has_err = false;
-        for segment in segments {
-            let (mut err_for_lt, mut err_for_ty, mut err_for_ct) = (false, false, false);
-            for arg in segment.args().args {
-                let (span, kind) = match arg {
-                    hir::GenericArg::Lifetime(lt) => {
-                        if err_for_lt {
-                            continue;
-                        }
-                        err_for_lt = true;
-                        has_err = true;
-                        (lt.span, "lifetime")
-                    }
-                    hir::GenericArg::Type(ty) => {
-                        if err_for_ty {
-                            continue;
-                        }
-                        err_for_ty = true;
-                        has_err = true;
-                        (ty.span, "type")
-                    }
-                    hir::GenericArg::Const(ct) => {
-                        if err_for_ct {
-                            continue;
-                        }
-                        err_for_ct = true;
-                        has_err = true;
-                        (ct.span, "const")
-                    }
-                    hir::GenericArg::Infer(inf) => {
-                        if err_for_ty {
-                            continue;
-                        }
-                        has_err = true;
-                        err_for_ty = true;
-                        (inf.span, "generic")
-                    }
-                };
-                let mut err = struct_span_err!(
-                    self.tcx().sess,
-                    span,
-                    E0109,
-                    "{} arguments are not allowed for this type",
-                    kind,
-                );
-                err.span_label(span, format!("{} argument not allowed", kind));
-                err.emit();
-                if err_for_lt && err_for_ty && err_for_ct {
-                    break;
-                }
-            }
+        let args = segments.clone().flat_map(|segment| segment.args().args);
 
+        let (lt, ty, ct, inf) =
+            args.clone().fold((false, false, false, false), |(lt, ty, ct, inf), arg| match arg {
+                hir::GenericArg::Lifetime(_) => (true, ty, ct, inf),
+                hir::GenericArg::Type(_) => (lt, true, ct, inf),
+                hir::GenericArg::Const(_) => (lt, ty, true, inf),
+                hir::GenericArg::Infer(_) => (lt, ty, ct, true),
+            });
+        let mut emitted = false;
+        if lt || ty || ct || inf {
+            let types_and_spans: Vec<_> = segments
+                .clone()
+                .flat_map(|segment| {
+                    segment.res.and_then(|res| {
+                        if segment.args().args.is_empty() {
+                            None
+                        } else {
+                            Some((
+                            match res {
+                                Res::PrimTy(ty) => format!("{} `{}`", res.descr(), ty.name()),
+                                Res::Def(_, def_id)
+                                if let Some(name) = self.tcx().opt_item_name(def_id) => {
+                                    format!("{} `{name}`", res.descr())
+                                }
+                                Res::Err => "this type".to_string(),
+                                _ => res.descr().to_string(),
+                            },
+                            segment.ident.span,
+                        ))
+                        }
+                    })
+                })
+                .collect();
+            let this_type = match &types_and_spans[..] {
+                [.., _, (last, _)] => format!(
+                    "{} and {last}",
+                    types_and_spans[..types_and_spans.len() - 1]
+                        .iter()
+                        .map(|(x, _)| x.as_str())
+                        .intersperse(&", ")
+                        .collect::<String>()
+                ),
+                [(only, _)] => only.to_string(),
+                [] => "this type".to_string(),
+            };
+
+            let arg_spans: Vec<Span> = args.map(|arg| arg.span()).collect();
+
+            let mut kinds = Vec::with_capacity(4);
+            if lt {
+                kinds.push("lifetime");
+            }
+            if ty {
+                kinds.push("type");
+            }
+            if ct {
+                kinds.push("const");
+            }
+            if inf {
+                kinds.push("generic");
+            }
+            let (kind, s) = match kinds[..] {
+                [.., _, last] => (
+                    format!(
+                        "{} and {last}",
+                        kinds[..kinds.len() - 1]
+                            .iter()
+                            .map(|&x| x)
+                            .intersperse(", ")
+                            .collect::<String>()
+                    ),
+                    "s",
+                ),
+                [only] => (format!("{only}"), ""),
+                [] => unreachable!(),
+            };
+            let last_span = *arg_spans.last().unwrap();
+            let span: MultiSpan = arg_spans.into();
+            let mut err = struct_span_err!(
+                self.tcx().sess,
+                span,
+                E0109,
+                "{kind} arguments are not allowed on {this_type}",
+            );
+            err.span_label(last_span, format!("{kind} argument{s} not allowed"));
+            for (what, span) in types_and_spans {
+                err.span_label(span, format!("not allowed on {what}"));
+            }
+            extend(&mut err);
+            err.emit();
+            emitted = true;
+        }
+
+        for segment in segments {
             // Only emit the first error to avoid overloading the user with error messages.
             if let [binding, ..] = segment.args().bindings {
-                has_err = true;
                 Self::prohibit_assoc_ty_binding(self.tcx(), binding.span);
+                return true;
             }
         }
-        has_err
+        emitted
     }
 
     // FIXME(eddyb, varkor) handle type paths here too, not just value ones.
@@ -2229,7 +2361,9 @@
                 // Check for desugared `impl Trait`.
                 assert!(ty::is_impl_trait_defn(tcx, did).is_none());
                 let item_segment = path.segments.split_last().unwrap();
-                self.prohibit_generics(item_segment.1);
+                self.prohibit_generics(item_segment.1.iter(), |err| {
+                    err.note("`impl Trait` types can't have type parameters");
+                });
                 let substs = self.ast_path_substs_for_ty(span, did, item_segment.0);
                 self.normalize_ty(span, tcx.mk_opaque(did, substs))
             }
@@ -2242,7 +2376,7 @@
                 did,
             ) => {
                 assert_eq!(opt_self_ty, None);
-                self.prohibit_generics(path.segments.split_last().unwrap().1);
+                self.prohibit_generics(path.segments.split_last().unwrap().1.iter(), |_| {});
                 self.ast_path_to_ty(span, did, path.segments.last().unwrap())
             }
             Res::Def(kind @ DefKind::Variant, def_id) if permit_variants => {
@@ -2254,18 +2388,26 @@
                     self.def_ids_for_value_path_segments(path.segments, None, kind, def_id);
                 let generic_segs: FxHashSet<_> =
                     path_segs.iter().map(|PathSeg(_, index)| index).collect();
-                self.prohibit_generics(path.segments.iter().enumerate().filter_map(
-                    |(index, seg)| {
+                self.prohibit_generics(
+                    path.segments.iter().enumerate().filter_map(|(index, seg)| {
                         if !generic_segs.contains(&index) { Some(seg) } else { None }
+                    }),
+                    |err| {
+                        err.note("enum variants can't have type parameters");
                     },
-                ));
+                );
 
                 let PathSeg(def_id, index) = path_segs.last().unwrap();
                 self.ast_path_to_ty(span, *def_id, &path.segments[*index])
             }
             Res::Def(DefKind::TyParam, def_id) => {
                 assert_eq!(opt_self_ty, None);
-                self.prohibit_generics(path.segments);
+                self.prohibit_generics(path.segments.iter(), |err| {
+                    if let Some(span) = tcx.def_ident_span(def_id) {
+                        let name = tcx.item_name(def_id);
+                        err.span_note(span, &format!("type parameter `{name}` defined here"));
+                    }
+                });
 
                 let def_id = def_id.expect_local();
                 let item_def_id = tcx.hir().ty_param_owner(def_id);
@@ -2276,15 +2418,81 @@
             Res::SelfTy { trait_: Some(_), alias_to: None } => {
                 // `Self` in trait or type alias.
                 assert_eq!(opt_self_ty, None);
-                self.prohibit_generics(path.segments);
+                self.prohibit_generics(path.segments.iter(), |err| {
+                    if let [hir::PathSegment { args: Some(args), ident, .. }] = &path.segments[..] {
+                        err.span_suggestion_verbose(
+                            ident.span.shrink_to_hi().to(args.span_ext),
+                            "the `Self` type doesn't accept type parameters",
+                            "",
+                            Applicability::MaybeIncorrect,
+                        );
+                    }
+                });
                 tcx.types.self_param
             }
             Res::SelfTy { trait_: _, alias_to: Some((def_id, forbid_generic)) } => {
                 // `Self` in impl (we know the concrete type).
                 assert_eq!(opt_self_ty, None);
-                self.prohibit_generics(path.segments);
                 // Try to evaluate any array length constants.
                 let ty = tcx.at(span).type_of(def_id);
+                let span_of_impl = tcx.span_of_impl(def_id);
+                self.prohibit_generics(path.segments.iter(), |err| {
+                    let def_id = match *ty.kind() {
+                        ty::Adt(self_def, _) => self_def.did(),
+                        _ => return,
+                    };
+
+                    let type_name = tcx.item_name(def_id);
+                    let span_of_ty = tcx.def_ident_span(def_id);
+                    let generics = tcx.generics_of(def_id).count();
+
+                    let msg = format!("`Self` is of type `{ty}`");
+                    if let (Ok(i_sp), Some(t_sp)) = (span_of_impl, span_of_ty) {
+                        let i_sp = tcx.sess.source_map().guess_head_span(i_sp);
+                        let mut span: MultiSpan = vec![t_sp].into();
+                        span.push_span_label(
+                            i_sp,
+                            &format!("`Self` is on type `{type_name}` in this `impl`"),
+                        );
+                        let mut postfix = "";
+                        if generics == 0 {
+                            postfix = ", which doesn't have generic parameters";
+                        }
+                        span.push_span_label(
+                            t_sp,
+                            &format!("`Self` corresponds to this type{postfix}"),
+                        );
+                        err.span_note(span, &msg);
+                    } else {
+                        err.note(&msg);
+                    }
+                    for segment in path.segments {
+                        if let Some(args) = segment.args && segment.ident.name == kw::SelfUpper {
+                            if generics == 0 {
+                                // FIXME(estebank): we could also verify that the arguments being
+                                // work for the `enum`, instead of just looking if it takes *any*.
+                                err.span_suggestion_verbose(
+                                    segment.ident.span.shrink_to_hi().to(args.span_ext),
+                                    "the `Self` type doesn't accept type parameters",
+                                    "",
+                                    Applicability::MachineApplicable,
+                                );
+                                return;
+                            } else {
+                                err.span_suggestion_verbose(
+                                    segment.ident.span,
+                                    format!(
+                                        "the `Self` type doesn't accept type parameters, use the \
+                                        concrete type's name `{type_name}` instead if you want to \
+                                        specify its type parameters"
+                                    ),
+                                    type_name.to_string(),
+                                    Applicability::MaybeIncorrect,
+                                );
+                            }
+                        }
+                    }
+                });
                 // HACK(min_const_generics): Forbid generic `Self` types
                 // here as we can't easily do that during nameres.
                 //
@@ -2324,7 +2532,7 @@
             }
             Res::Def(DefKind::AssocTy, def_id) => {
                 debug_assert!(path.segments.len() >= 2);
-                self.prohibit_generics(&path.segments[..path.segments.len() - 2]);
+                self.prohibit_generics(path.segments[..path.segments.len() - 2].iter(), |_| {});
                 self.qpath_to_ty(
                     span,
                     opt_self_ty,
@@ -2335,7 +2543,19 @@
             }
             Res::PrimTy(prim_ty) => {
                 assert_eq!(opt_self_ty, None);
-                self.prohibit_generics(path.segments);
+                self.prohibit_generics(path.segments.iter(), |err| {
+                    let name = prim_ty.name_str();
+                    for segment in path.segments {
+                        if let Some(args) = segment.args {
+                            err.span_suggestion_verbose(
+                                segment.ident.span.shrink_to_hi().to(args.span_ext),
+                                &format!("primitive type `{name}` doesn't have generic parameters"),
+                                "",
+                                Applicability::MaybeIncorrect,
+                            );
+                        }
+                    }
+                });
                 match prim_ty {
                     hir::PrimTy::Bool => tcx.types.bool,
                     hir::PrimTy::Char => tcx.types.char,
@@ -2410,29 +2630,16 @@
                 let def_id = item_id.def_id.to_def_id();
 
                 match opaque_ty.kind {
-                    hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => self
-                        .impl_trait_ty_to_ty(
-                            def_id,
-                            lifetimes,
-                            matches!(
-                                origin,
-                                hir::OpaqueTyOrigin::FnReturn(..)
-                                    | hir::OpaqueTyOrigin::AsyncFn(..)
-                            ),
-                        ),
+                    hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => {
+                        self.impl_trait_ty_to_ty(def_id, lifetimes, origin)
+                    }
                     ref i => bug!("`impl Trait` pointed to non-opaque type?? {:#?}", i),
                 }
             }
             hir::TyKind::Path(hir::QPath::TypeRelative(ref qself, ref segment)) => {
                 debug!(?qself, ?segment);
                 let ty = self.ast_ty_to_ty_inner(qself, false, true);
-
-                let res = if let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = qself.kind {
-                    path.res
-                } else {
-                    Res::Err
-                };
-                self.associated_path_to_ty(ast_ty.hir_id, ast_ty.span, ty, res, segment, false)
+                self.associated_path_to_ty(ast_ty.hir_id, ast_ty.span, ty, qself, segment, false)
                     .map(|(ty, _, _)| ty)
                     .unwrap_or_else(|_| tcx.ty_error())
             }
@@ -2494,7 +2701,7 @@
         &self,
         def_id: DefId,
         lifetimes: &[hir::GenericArg<'_>],
-        replace_parent_lifetimes: bool,
+        origin: OpaqueTyOrigin,
     ) -> Ty<'tcx> {
         debug!("impl_trait_ty_to_ty(def_id={:?}, lifetimes={:?})", def_id, lifetimes);
         let tcx = self.tcx();
@@ -2524,7 +2731,12 @@
                     // For `impl Trait` in the types of statics, constants,
                     // locals and type aliases. These capture all parent
                     // lifetimes, so they can use their identity subst.
-                    GenericParamDefKind::Lifetime if replace_parent_lifetimes => {
+                    GenericParamDefKind::Lifetime
+                        if matches!(
+                            origin,
+                            hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..)
+                        ) =>
+                    {
                         tcx.lifetimes.re_static.into()
                     }
                     _ => tcx.mk_param_from_def(param),
@@ -2709,13 +2921,15 @@
     ) {
         for br in referenced_regions.difference(&constrained_regions) {
             let br_name = match *br {
+                ty::BrNamed(_, kw::UnderscoreLifetime) | ty::BrAnon(_) | ty::BrEnv => {
+                    "an anonymous lifetime".to_string()
+                }
                 ty::BrNamed(_, name) => format!("lifetime `{}`", name),
-                ty::BrAnon(_) | ty::BrEnv => "an anonymous lifetime".to_string(),
             };
 
             let mut err = generate_err(&br_name);
 
-            if let ty::BrAnon(_) = *br {
+            if let ty::BrNamed(_, kw::UnderscoreLifetime) | ty::BrAnon(_) = *br {
                 // The only way for an anonymous lifetime to wind up
                 // in the return type but **also** be unconstrained is
                 // if it only appears in "associated types" in the
diff --git a/compiler/rustc_typeck/src/check/_match.rs b/compiler/rustc_typeck/src/check/_match.rs
index 1c7e7c9..bbdf1da 100644
--- a/compiler/rustc_typeck/src/check/_match.rs
+++ b/compiler/rustc_typeck/src/check/_match.rs
@@ -56,6 +56,7 @@
         let mut all_arms_diverge = Diverges::WarnedAlways;
 
         let expected = orig_expected.adjust_for_branches(self);
+        debug!(?expected);
 
         let mut coercion = {
             let coerce_first = match expected {
@@ -82,13 +83,8 @@
                     hir::Guard::If(e) => {
                         self.check_expr_has_type_or_error(e, tcx.types.bool, |_| {});
                     }
-                    hir::Guard::IfLet(pat, e) => {
-                        let scrutinee_ty = self.demand_scrutinee_type(
-                            e,
-                            pat.contains_explicit_ref_binding(),
-                            false,
-                        );
-                        self.check_pat_top(&pat, scrutinee_ty, None, true);
+                    hir::Guard::IfLet(l) => {
+                        self.check_expr_let(l);
                     }
                 };
             }
@@ -132,6 +128,12 @@
                 Some(&arm.body),
                 arm_ty,
                 Some(&mut |err: &mut Diagnostic| {
+                    let Some(ret) = self.ret_type_span else {
+                        return;
+                    };
+                    let Expectation::IsLast(stmt) = orig_expected else {
+                        return
+                    };
                     let can_coerce_to_return_ty = match self.ret_coercion.as_ref() {
                         Some(ret_coercion) if self.in_tail_expr => {
                             let ret_ty = ret_coercion.borrow().expected_ty();
@@ -143,38 +145,38 @@
                         }
                         _ => false,
                     };
-                    if let (Expectation::IsLast(stmt), Some(ret), true) =
-                        (orig_expected, self.ret_type_span, can_coerce_to_return_ty)
-                    {
-                        let semi_span = expr.span.shrink_to_hi().with_hi(stmt.hi());
-                        let mut ret_span: MultiSpan = semi_span.into();
-                        ret_span.push_span_label(
-                            expr.span,
-                            "this could be implicitly returned but it is a statement, not a \
-                                tail expression"
-                                .to_owned(),
-                        );
-                        ret_span.push_span_label(
-                            ret,
-                            "the `match` arms can conform to this return type".to_owned(),
-                        );
-                        ret_span.push_span_label(
-                            semi_span,
-                            "the `match` is a statement because of this semicolon, consider \
-                                removing it"
-                                .to_owned(),
-                        );
-                        err.span_note(
-                            ret_span,
-                            "you might have meant to return the `match` expression",
-                        );
-                        err.tool_only_span_suggestion(
-                            semi_span,
-                            "remove this semicolon",
-                            String::new(),
-                            Applicability::MaybeIncorrect,
-                        );
+                    if !can_coerce_to_return_ty {
+                        return;
                     }
+
+                    let semi_span = expr.span.shrink_to_hi().with_hi(stmt.hi());
+                    let mut ret_span: MultiSpan = semi_span.into();
+                    ret_span.push_span_label(
+                        expr.span,
+                        "this could be implicitly returned but it is a statement, not a \
+                            tail expression"
+                            .to_owned(),
+                    );
+                    ret_span.push_span_label(
+                        ret,
+                        "the `match` arms can conform to this return type".to_owned(),
+                    );
+                    ret_span.push_span_label(
+                        semi_span,
+                        "the `match` is a statement because of this semicolon, consider \
+                            removing it"
+                            .to_owned(),
+                    );
+                    err.span_note(
+                        ret_span,
+                        "you might have meant to return the `match` expression",
+                    );
+                    err.tool_only_span_suggestion(
+                        semi_span,
+                        "remove this semicolon",
+                        "",
+                        Applicability::MaybeIncorrect,
+                    );
                 }),
                 false,
             );
@@ -204,7 +206,9 @@
         // We won't diverge unless the scrutinee or all arms diverge.
         self.diverges.set(scrut_diverges | all_arms_diverge);
 
-        coercion.complete(self)
+        let match_ty = coercion.complete(self);
+        debug!(?match_ty);
+        match_ty
     }
 
     fn get_appropriate_arm_semicolon_removal_span(
diff --git a/compiler/rustc_typeck/src/check/callee.rs b/compiler/rustc_typeck/src/check/callee.rs
index 0a84d41..83a8c5e 100644
--- a/compiler/rustc_typeck/src/check/callee.rs
+++ b/compiler/rustc_typeck/src/check/callee.rs
@@ -152,13 +152,11 @@
                 // fnmut vs fnonce. If so, we have to defer further processing.
                 if self.closure_kind(substs).is_none() {
                     let closure_sig = substs.as_closure().sig();
-                    let closure_sig = self
-                        .replace_bound_vars_with_fresh_vars(
-                            call_expr.span,
-                            infer::FnCall,
-                            closure_sig,
-                        )
-                        .0;
+                    let closure_sig = self.replace_bound_vars_with_fresh_vars(
+                        call_expr.span,
+                        infer::FnCall,
+                        closure_sig,
+                    );
                     let adjustments = self.adjust_steps(autoderef);
                     self.record_deferred_call_resolution(
                         def_id,
@@ -285,11 +283,13 @@
         let hir_id = self.tcx.hir().get_parent_node(hir_id);
         let parent_node = self.tcx.hir().get(hir_id);
         if let (
-            hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(_, _, _, sp, ..), .. }),
+            hir::Node::Expr(hir::Expr {
+                kind: hir::ExprKind::Closure { fn_decl_span, .. }, ..
+            }),
             hir::ExprKind::Block(..),
         ) = (parent_node, callee_node)
         {
-            let start = sp.shrink_to_lo();
+            let start = fn_decl_span.shrink_to_lo();
             let end = callee_span.shrink_to_hi();
             err.multipart_suggestion(
                 "if you meant to create this closure and immediately call it, surround the \
@@ -321,7 +321,7 @@
             err.span_suggestion(
                 start,
                 "consider separating array elements with a comma",
-                ",".to_string(),
+                ",",
                 Applicability::MaybeIncorrect,
             );
             return true;
@@ -408,7 +408,7 @@
                         &format!(
                             "`{path}` is a unit variant, you need to write it without the parentheses",
                         ),
-                        String::new(),
+                        "",
                         Applicability::MachineApplicable,
                     );
                 }
@@ -428,7 +428,7 @@
                             err.span_suggestion(
                                 callee_expr.span.shrink_to_hi(),
                                 "consider using a semicolon here",
-                                ";".to_owned(),
+                                ";",
                                 Applicability::MaybeIncorrect,
                             );
                         }
@@ -503,8 +503,7 @@
         // renormalize the associated types at this point, since they
         // previously appeared within a `Binder<>` and hence would not
         // have been normalized before.
-        let fn_sig =
-            self.replace_bound_vars_with_fresh_vars(call_expr.span, infer::FnCall, fn_sig).0;
+        let fn_sig = self.replace_bound_vars_with_fresh_vars(call_expr.span, infer::FnCall, fn_sig);
         let fn_sig = self.normalize_associated_types_in(call_expr.span, fn_sig);
 
         // Call the generic checker.
diff --git a/compiler/rustc_typeck/src/check/cast.rs b/compiler/rustc_typeck/src/check/cast.rs
index a153997..7d5d684 100644
--- a/compiler/rustc_typeck/src/check/cast.rs
+++ b/compiler/rustc_typeck/src/check/cast.rs
@@ -347,16 +347,22 @@
                 );
                 err.span_label(self.span, "invalid cast");
                 if self.expr_ty.is_numeric() {
-                    err.span_help(
-                        self.span,
-                        if self.expr_ty == fcx.tcx.types.i8 {
-                            "try casting from `u8` instead"
-                        } else if self.expr_ty == fcx.tcx.types.u32 {
-                            "try `char::from_u32` instead"
-                        } else {
-                            "try `char::from_u32` instead (via a `u32`)"
-                        },
-                    );
+                    if self.expr_ty == fcx.tcx.types.u32 {
+                        match fcx.tcx.sess.source_map().span_to_snippet(self.expr.span) {
+                            Ok(snippet) => err.span_suggestion(
+                                self.span,
+                                "try `char::from_u32` instead",
+                                format!("char::from_u32({snippet})"),
+                                Applicability::MachineApplicable,
+                            ),
+
+                            Err(_) => err.span_help(self.span, "try `char::from_u32` instead"),
+                        };
+                    } else if self.expr_ty == fcx.tcx.types.i8 {
+                        err.span_help(self.span, "try casting from `u8` instead");
+                    } else {
+                        err.span_help(self.span, "try `char::from_u32` instead (via a `u32`)");
+                    };
                 }
                 err.emit();
             }
@@ -955,7 +961,7 @@
         }
     }
 
-    fn try_coercion_cast(&self, fcx: &FnCtxt<'a, 'tcx>) -> Result<(), ty::error::TypeError<'_>> {
+    fn try_coercion_cast(&self, fcx: &FnCtxt<'a, 'tcx>) -> Result<(), ty::error::TypeError<'tcx>> {
         match fcx.try_coerce(self.expr, self.expr_ty, self.cast_ty, AllowTwoPhase::No, None) {
             Ok(_) => Ok(()),
             Err(err) => Err(err),
diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs
index da51633..45c011b 100644
--- a/compiler/rustc_typeck/src/check/check.rs
+++ b/compiler/rustc_typeck/src/check/check.rs
@@ -1,3 +1,5 @@
+use crate::check::wfcheck::for_item;
+
 use super::coercion::CoerceMany;
 use super::compare_method::check_type_bounds;
 use super::compare_method::{compare_const_impl, compare_impl_method, compare_ty_impl};
@@ -6,19 +8,19 @@
 use rustc_attr as attr;
 use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan};
 use rustc_hir as hir;
+use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::intravisit::Visitor;
 use rustc_hir::lang_items::LangItem;
-use rustc_hir::{def::Res, ItemKind, Node, PathSegment};
+use rustc_hir::{ItemKind, Node, PathSegment};
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt};
 use rustc_infer::traits::Obligation;
 use rustc_middle::hir::nested_filter;
-use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::layout::{LayoutError, MAX_SIMD_LANES};
 use rustc_middle::ty::subst::GenericArgKind;
 use rustc_middle::ty::util::{Discr, IntTypeExt};
-use rustc_middle::ty::{self, ParamEnv, ToPredicate, Ty, TyCtxt};
+use rustc_middle::ty::{self, ParamEnv, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable};
 use rustc_session::lint::builtin::{UNINHABITED_STATIC, UNSUPPORTED_CALLING_CONVENTIONS};
 use rustc_span::symbol::sym;
 use rustc_span::{self, Span};
@@ -27,7 +29,6 @@
 use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
 use rustc_ty_utils::representability::{self, Representability};
 
-use rustc_hir::def::DefKind;
 use std::iter;
 use std::ops::ControlFlow;
 
@@ -91,7 +92,6 @@
     fcx.return_type_pre_known = return_type_pre_known;
 
     let tcx = fcx.tcx;
-    let sess = tcx.sess;
     let hir = tcx.hir();
 
     let declared_ret_ty = fn_sig.output();
@@ -101,8 +101,13 @@
             declared_ret_ty,
             body.value.hir_id,
             DUMMY_SP,
+            traits::ObligationCauseCode::OpaqueReturnType(None),
             param_env,
         ));
+    // If we replaced declared_ret_ty with infer vars, then we must be infering
+    // an opaque type, so set a flag so we can improve diagnostics.
+    fcx.return_type_has_opaque = ret_ty != declared_ret_ty;
+
     fcx.ret_coercion = Some(RefCell::new(CoerceMany::new(ret_ty)));
     fcx.ret_type_span = Some(decl.output.span());
 
@@ -124,7 +129,7 @@
                     ..
                 }) => Some(header),
                 // Closures are RustCall, but they tuple their arguments, so shouldn't be checked
-                Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(..), .. }) => None,
+                Node::Expr(hir::Expr { kind: hir::ExprKind::Closure { .. }, .. }) => None,
                 node => bug!("Item being checked wasn't a function/closure: {:?}", node),
             };
 
@@ -257,87 +262,125 @@
     if let Some(panic_impl_did) = tcx.lang_items().panic_impl()
         && panic_impl_did == hir.local_def_id(fn_id).to_def_id()
     {
-        if let Some(panic_info_did) = tcx.lang_items().panic_info() {
-            if *declared_ret_ty.kind() != ty::Never {
-                sess.span_err(decl.output.span(), "return type should be `!`");
-            }
-
-            let inputs = fn_sig.inputs();
-            let span = hir.span(fn_id);
-            if inputs.len() == 1 {
-                let arg_is_panic_info = match *inputs[0].kind() {
-                    ty::Ref(region, ty, mutbl) => match *ty.kind() {
-                        ty::Adt(ref adt, _) => {
-                            adt.did() == panic_info_did
-                                && mutbl == hir::Mutability::Not
-                                && !region.is_static()
-                        }
-                        _ => false,
-                    },
-                    _ => false,
-                };
-
-                if !arg_is_panic_info {
-                    sess.span_err(decl.inputs[0].span, "argument should be `&PanicInfo`");
-                }
-
-                if let Node::Item(item) = hir.get(fn_id)
-                    && let ItemKind::Fn(_, ref generics, _) = item.kind
-                    && !generics.params.is_empty()
-                {
-                            sess.span_err(span, "should have no type parameters");
-                        }
-            } else {
-                let span = sess.source_map().guess_head_span(span);
-                sess.span_err(span, "function should have one argument");
-            }
-        } else {
-            sess.err("language item required, but not found: `panic_info`");
-        }
+        check_panic_info_fn(tcx, panic_impl_did.expect_local(), fn_sig, decl, declared_ret_ty);
     }
 
     // Check that a function marked as `#[alloc_error_handler]` has signature `fn(Layout) -> !`
     if let Some(alloc_error_handler_did) = tcx.lang_items().oom()
         && alloc_error_handler_did == hir.local_def_id(fn_id).to_def_id()
     {
-        if let Some(alloc_layout_did) = tcx.lang_items().alloc_layout() {
-            if *declared_ret_ty.kind() != ty::Never {
-                sess.span_err(decl.output.span(), "return type should be `!`");
-            }
-
-            let inputs = fn_sig.inputs();
-            let span = hir.span(fn_id);
-            if inputs.len() == 1 {
-                let arg_is_alloc_layout = match inputs[0].kind() {
-                    ty::Adt(ref adt, _) => adt.did() == alloc_layout_did,
-                    _ => false,
-                };
-
-                if !arg_is_alloc_layout {
-                    sess.span_err(decl.inputs[0].span, "argument should be `Layout`");
-                }
-
-                if let Node::Item(item) = hir.get(fn_id)
-                    && let ItemKind::Fn(_, ref generics, _) = item.kind
-                    && !generics.params.is_empty()
-                {
-                            sess.span_err(
-                                span,
-                        "`#[alloc_error_handler]` function should have no type parameters",
-                            );
-                        }
-            } else {
-                let span = sess.source_map().guess_head_span(span);
-                sess.span_err(span, "function should have one argument");
-            }
-        } else {
-            sess.err("language item required, but not found: `alloc_layout`");
-        }
+        check_alloc_error_fn(tcx, alloc_error_handler_did.expect_local(), fn_sig, decl, declared_ret_ty);
     }
 
     (fcx, gen_ty)
 }
 
+fn check_panic_info_fn(
+    tcx: TyCtxt<'_>,
+    fn_id: LocalDefId,
+    fn_sig: ty::FnSig<'_>,
+    decl: &hir::FnDecl<'_>,
+    declared_ret_ty: Ty<'_>,
+) {
+    let Some(panic_info_did) = tcx.lang_items().panic_info() else {
+        tcx.sess.err("language item required, but not found: `panic_info`");
+        return;
+    };
+
+    if *declared_ret_ty.kind() != ty::Never {
+        tcx.sess.span_err(decl.output.span(), "return type should be `!`");
+    }
+
+    let span = tcx.def_span(fn_id);
+    let inputs = fn_sig.inputs();
+    if inputs.len() != 1 {
+        let span = tcx.sess.source_map().guess_head_span(span);
+        tcx.sess.span_err(span, "function should have one argument");
+        return;
+    }
+
+    let arg_is_panic_info = match *inputs[0].kind() {
+        ty::Ref(region, ty, mutbl) => match *ty.kind() {
+            ty::Adt(ref adt, _) => {
+                adt.did() == panic_info_did && mutbl == hir::Mutability::Not && !region.is_static()
+            }
+            _ => false,
+        },
+        _ => false,
+    };
+
+    if !arg_is_panic_info {
+        tcx.sess.span_err(decl.inputs[0].span, "argument should be `&PanicInfo`");
+    }
+
+    let DefKind::Fn = tcx.def_kind(fn_id) else {
+        let span = tcx.def_span(fn_id);
+        tcx.sess.span_err(span, "should be a function");
+        return;
+    };
+
+    let generic_counts = tcx.generics_of(fn_id).own_counts();
+    if generic_counts.types != 0 {
+        let span = tcx.def_span(fn_id);
+        tcx.sess.span_err(span, "should have no type parameters");
+    }
+    if generic_counts.consts != 0 {
+        let span = tcx.def_span(fn_id);
+        tcx.sess.span_err(span, "should have no const parameters");
+    }
+}
+
+fn check_alloc_error_fn(
+    tcx: TyCtxt<'_>,
+    fn_id: LocalDefId,
+    fn_sig: ty::FnSig<'_>,
+    decl: &hir::FnDecl<'_>,
+    declared_ret_ty: Ty<'_>,
+) {
+    let Some(alloc_layout_did) = tcx.lang_items().alloc_layout() else {
+        tcx.sess.err("language item required, but not found: `alloc_layout`");
+        return;
+    };
+
+    if *declared_ret_ty.kind() != ty::Never {
+        tcx.sess.span_err(decl.output.span(), "return type should be `!`");
+    }
+
+    let inputs = fn_sig.inputs();
+    if inputs.len() != 1 {
+        let span = tcx.def_span(fn_id);
+        let span = tcx.sess.source_map().guess_head_span(span);
+        tcx.sess.span_err(span, "function should have one argument");
+        return;
+    }
+
+    let arg_is_alloc_layout = match inputs[0].kind() {
+        ty::Adt(ref adt, _) => adt.did() == alloc_layout_did,
+        _ => false,
+    };
+
+    if !arg_is_alloc_layout {
+        tcx.sess.span_err(decl.inputs[0].span, "argument should be `Layout`");
+    }
+
+    let DefKind::Fn = tcx.def_kind(fn_id) else {
+        let span = tcx.def_span(fn_id);
+        tcx.sess.span_err(span, "`#[alloc_error_handler]` should be a function");
+        return;
+    };
+
+    let generic_counts = tcx.generics_of(fn_id).own_counts();
+    if generic_counts.types != 0 {
+        let span = tcx.def_span(fn_id);
+        tcx.sess.span_err(span, "`#[alloc_error_handler]` function should have no type parameters");
+    }
+    if generic_counts.consts != 0 {
+        let span = tcx.def_span(fn_id);
+        tcx.sess
+            .span_err(span, "`#[alloc_error_handler]` function should have no const parameters");
+    }
+}
+
 fn check_struct(tcx: TyCtxt<'_>, def_id: LocalDefId, span: Span) {
     let def = tcx.adt_def(def_id);
     def.destructor(tcx); // force the destructor to be evaluated
@@ -501,7 +544,7 @@
         }
 
         fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
-            if let ty::ConstKind::Unevaluated(..) = c.val() {
+            if let ty::ConstKind::Unevaluated(..) = c.kind() {
                 // FIXME(#72219) We currently don't detect lifetimes within substs
                 // which would violate this check. Even though the particular substitution is not used
                 // within the const, this should still be fixed.
@@ -870,6 +913,14 @@
                 }
             }
         }
+        DefKind::GlobalAsm => {
+            let it = tcx.hir().item(id);
+            let hir::ItemKind::GlobalAsm(asm) = it.kind else { span_bug!(it.span, "DefKind::GlobalAsm but got {:#?}", it) };
+            for_item(tcx, it).with_fcx(|fcx| {
+                fcx.check_asm(asm, it.hir_id());
+                Default::default()
+            })
+        }
         _ => {}
     }
 }
@@ -1365,6 +1416,8 @@
     }
 
     let mut disr_vals: Vec<Discr<'tcx>> = Vec::with_capacity(vs.len());
+    // This tracks the previous variant span (in the loop) incase we need it for diagnostics
+    let mut prev_variant_span: Span = DUMMY_SP;
     for ((_, discr), v) in iter::zip(def.discriminants(tcx), vs) {
         // Check for duplicate discriminant values
         if let Some(i) = disr_vals.iter().position(|&x| x.val == discr.val) {
@@ -1379,42 +1432,59 @@
                 Some(ref expr) => tcx.hir().span(expr.hir_id),
                 None => v.span,
             };
-            let display_discr = display_discriminant_value(tcx, v, discr.val);
-            let display_discr_i = display_discriminant_value(tcx, variant_i, disr_vals[i].val);
-            struct_span_err!(
+            let display_discr = format_discriminant_overflow(tcx, v, discr);
+            let display_discr_i = format_discriminant_overflow(tcx, variant_i, disr_vals[i]);
+            let no_disr = v.disr_expr.is_none();
+            let mut err = struct_span_err!(
                 tcx.sess,
-                span,
+                sp,
                 E0081,
-                "discriminant value `{}` already exists",
-                discr.val,
-            )
-            .span_label(i_span, format!("first use of {display_discr_i}"))
-            .span_label(span, format!("enum already has {display_discr}"))
-            .emit();
+                "discriminant value `{}` assigned more than once",
+                discr,
+            );
+
+            err.span_label(i_span, format!("first assignment of {display_discr_i}"));
+            err.span_label(span, format!("second assignment of {display_discr}"));
+
+            if no_disr {
+                err.span_label(
+                    prev_variant_span,
+                    format!(
+                        "assigned discriminant for `{}` was incremented from this discriminant",
+                        v.ident
+                    ),
+                );
+            }
+            err.emit();
         }
+
         disr_vals.push(discr);
+        prev_variant_span = v.span;
     }
 
     check_representable(tcx, sp, def_id);
     check_transparent(tcx, sp, def);
 }
 
-/// Format an enum discriminant value for use in a diagnostic message.
-fn display_discriminant_value<'tcx>(
+/// In the case that a discriminant is both a duplicate and an overflowing literal,
+/// we insert both the assigned discriminant and the literal it overflowed from into the formatted
+/// output. Otherwise we format the discriminant normally.
+fn format_discriminant_overflow<'tcx>(
     tcx: TyCtxt<'tcx>,
     variant: &hir::Variant<'_>,
-    evaluated: u128,
+    dis: Discr<'tcx>,
 ) -> String {
     if let Some(expr) = &variant.disr_expr {
         let body = &tcx.hir().body(expr.body).value;
         if let hir::ExprKind::Lit(lit) = &body.kind
             && let rustc_ast::LitKind::Int(lit_value, _int_kind) = &lit.node
-            && evaluated != *lit_value
+            && dis.val != *lit_value
         {
-                    return format!("`{evaluated}` (overflowed from `{lit_value}`)");
+                    return format!("`{dis}` (overflowed from `{lit_value}`)");
         }
     }
-    format!("`{}`", evaluated)
+
+    format!("`{dis}`")
 }
 
 pub(super) fn check_type_params_are_used<'tcx>(
diff --git a/compiler/rustc_typeck/src/check/closure.rs b/compiler/rustc_typeck/src/check/closure.rs
index c8fe046..cce1130 100644
--- a/compiler/rustc_typeck/src/check/closure.rs
+++ b/compiler/rustc_typeck/src/check/closure.rs
@@ -10,6 +10,7 @@
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_infer::infer::LateBoundRegionConversionTime;
 use rustc_infer::infer::{InferOk, InferResult};
+use rustc_infer::traits::ObligationCauseCode;
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::subst::InternalSubsts;
 use rustc_middle::ty::{self, Ty};
@@ -550,7 +551,7 @@
                 expected_sigs.liberated_sig.inputs(), // `liberated_sig` is E'.
             ) {
                 // Instantiate (this part of..) S to S', i.e., with fresh variables.
-                let (supplied_ty, _) = self.infcx.replace_bound_vars_with_fresh_vars(
+                let supplied_ty = self.infcx.replace_bound_vars_with_fresh_vars(
                     hir_ty.span,
                     LateBoundRegionConversionTime::FnCall,
                     supplied_sig.inputs().rebind(supplied_ty),
@@ -563,7 +564,7 @@
                 all_obligations.extend(obligations);
             }
 
-            let (supplied_output_ty, _) = self.infcx.replace_bound_vars_with_fresh_vars(
+            let supplied_output_ty = self.infcx.replace_bound_vars_with_fresh_vars(
                 decl.output.span(),
                 LateBoundRegionConversionTime::FnCall,
                 supplied_sig.output(),
@@ -645,8 +646,13 @@
     }
 
     fn hide_parent_opaque_types(&self, ty: Ty<'tcx>, span: Span, body_id: hir::HirId) -> Ty<'tcx> {
-        let InferOk { value, obligations } =
-            self.replace_opaque_types_with_inference_vars(ty, body_id, span, self.param_env);
+        let InferOk { value, obligations } = self.replace_opaque_types_with_inference_vars(
+            ty,
+            body_id,
+            span,
+            ObligationCauseCode::MiscObligation,
+            self.param_env,
+        );
         self.register_predicates(obligations);
         value
     }
diff --git a/compiler/rustc_typeck/src/check/coercion.rs b/compiler/rustc_typeck/src/check/coercion.rs
index c563d57..43fc49c6 100644
--- a/compiler/rustc_typeck/src/check/coercion.rs
+++ b/compiler/rustc_typeck/src/check/coercion.rs
@@ -58,7 +58,8 @@
 use rustc_span::symbol::sym;
 use rustc_span::{self, BytePos, DesugaringKind, Span};
 use rustc_target::spec::abi::Abi;
-use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
+use rustc_trait_selection::infer::InferCtxtExt as _;
+use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
 use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode};
 
 use smallvec::{smallvec, SmallVec};
@@ -615,7 +616,7 @@
         )];
 
         let mut has_unsized_tuple_coercion = false;
-        let mut has_trait_upcasting_coercion = false;
+        let mut has_trait_upcasting_coercion = None;
 
         // Keep resolving `CoerceUnsized` and `Unsize` predicates to avoid
         // emitting a coercion in cases like `Foo<$1>` -> `Foo<$2>`, where
@@ -635,7 +636,7 @@
                             && data_a.principal_def_id() != data_b.principal_def_id()
                         {
                             debug!("coerce_unsized: found trait upcasting coercion");
-                            has_trait_upcasting_coercion = true;
+                            has_trait_upcasting_coercion = Some((self_ty, unsize_ty));
                         }
                         if let ty::Tuple(..) = unsize_ty.kind() {
                             debug!("coerce_unsized: found unsized tuple coercion");
@@ -706,14 +707,19 @@
             .emit();
         }
 
-        if has_trait_upcasting_coercion && !self.tcx().features().trait_upcasting {
-            feature_err(
+        if let Some((sub, sup)) = has_trait_upcasting_coercion
+            && !self.tcx().features().trait_upcasting
+        {
+            // Renders better when we erase regions, since they're not really the point here.
+            let (sub, sup) = self.tcx.erase_regions((sub, sup));
+            let mut err = feature_err(
                 &self.tcx.sess.parse_sess,
                 sym::trait_upcasting,
                 self.cause.span,
-                "trait upcasting coercion is experimental",
-            )
-            .emit();
+                &format!("cannot cast `{sub}` to `{sup}`, trait upcasting coercion is experimental"),
+            );
+            err.note(&format!("required when coercing `{source}` into `{target}`"));
+            err.emit();
         }
 
         Ok(coercion)
@@ -731,14 +737,27 @@
         F: FnOnce(Ty<'tcx>) -> Vec<Adjustment<'tcx>>,
         G: FnOnce(Ty<'tcx>) -> Vec<Adjustment<'tcx>>,
     {
-        if let ty::FnPtr(fn_ty_b) = b.kind()
-            && let (hir::Unsafety::Normal, hir::Unsafety::Unsafe) =
-                (fn_ty_a.unsafety(), fn_ty_b.unsafety())
-        {
-            let unsafe_a = self.tcx.safe_to_unsafe_fn_ty(fn_ty_a);
-            return self.unify_and(unsafe_a, b, to_unsafe);
-        }
-        self.unify_and(a, b, normal)
+        self.commit_unconditionally(|snapshot| {
+            let result = if let ty::FnPtr(fn_ty_b) = b.kind()
+                && let (hir::Unsafety::Normal, hir::Unsafety::Unsafe) =
+                    (fn_ty_a.unsafety(), fn_ty_b.unsafety())
+            {
+                let unsafe_a = self.tcx.safe_to_unsafe_fn_ty(fn_ty_a);
+                self.unify_and(unsafe_a, b, to_unsafe)
+            } else {
+                self.unify_and(a, b, normal)
+            };
+
+            // FIXME(#73154): This is a hack. Currently LUB can generate
+            // unsolvable constraints. Additionally, it returns `a`
+            // unconditionally, even when the "LUB" is `b`. In the future, we
+            // want the coerced type to be the actual supertype of these two,
+            // but for now, we want to just error to ensure we don't lock
+            // ourselves into a specific behavior with NLL.
+            self.leak_check(false, snapshot)?;
+
+            result
+        })
     }
 
     fn coerce_from_fn_pointer(
@@ -775,17 +794,19 @@
         match b.kind() {
             ty::FnPtr(b_sig) => {
                 let a_sig = a.fn_sig(self.tcx);
-                // Intrinsics are not coercible to function pointers
-                if a_sig.abi() == Abi::RustIntrinsic || a_sig.abi() == Abi::PlatformIntrinsic {
-                    return Err(TypeError::IntrinsicCast);
-                }
+                if let ty::FnDef(def_id, _) = *a.kind() {
+                    // Intrinsics are not coercible to function pointers
+                    if self.tcx.is_intrinsic(def_id) {
+                        return Err(TypeError::IntrinsicCast);
+                    }
 
-                // Safe `#[target_feature]` functions are not assignable to safe fn pointers (RFC 2396).
-                if let ty::FnDef(def_id, _) = *a.kind()
-                    && b_sig.unsafety() == hir::Unsafety::Normal
-                    && !self.tcx.codegen_fn_attrs(def_id).target_features.is_empty()
-                {
-                    return Err(TypeError::TargetFeatureCast(def_id));
+                    // Safe `#[target_feature]` functions are not assignable to safe fn pointers (RFC 2396).
+
+                    if b_sig.unsafety() == hir::Unsafety::Normal
+                        && !self.tcx.codegen_fn_attrs(def_id).target_features.is_empty()
+                    {
+                        return Err(TypeError::TargetFeatureCast(def_id));
+                    }
                 }
 
                 let InferOk { value: a_sig, obligations: o1 } =
@@ -960,6 +981,26 @@
             .find_map(|(ty, steps)| self.probe(|_| coerce.unify(ty, target)).ok().map(|_| steps))
     }
 
+    /// Given a type, this function will calculate and return the type given
+    /// for `<Ty as Deref>::Target` only if `Ty` also implements `DerefMut`.
+    ///
+    /// This function is for diagnostics only, since it does not register
+    /// trait or region sub-obligations. (presumably we could, but it's not
+    /// particularly important for diagnostics...)
+    pub fn deref_once_mutably_for_diagnostic(&self, expr_ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
+        self.autoderef(rustc_span::DUMMY_SP, expr_ty).nth(1).and_then(|(deref_ty, _)| {
+            self.infcx
+                .type_implements_trait(
+                    self.infcx.tcx.lang_items().deref_mut_trait()?,
+                    expr_ty,
+                    ty::List::empty(),
+                    self.param_env,
+                )
+                .may_apply()
+                .then(|| deref_ty)
+        })
+    }
+
     /// Given some expressions, their known unified type and another expression,
     /// tries to unify the types, potentially inserting coercions on any of the
     /// provided expressions and returns their LUB (aka "common supertype").
@@ -995,7 +1036,8 @@
         // Special-case that coercion alone cannot handle:
         // Function items or non-capturing closures of differing IDs or InternalSubsts.
         let (a_sig, b_sig) = {
-            let is_capturing_closure = |ty| {
+            #[allow(rustc::usage_of_ty_tykind)]
+            let is_capturing_closure = |ty: &ty::TyKind<'tcx>| {
                 if let &ty::Closure(closure_def_id, _substs) = ty {
                     self.tcx.upvars_mentioned(closure_def_id.expect_local()).is_some()
                 } else {
@@ -1105,8 +1147,8 @@
                     let (adjustments, target) = self.register_infer_ok_obligations(ok);
                     self.apply_adjustments(new, adjustments);
                     debug!(
-                        "coercion::try_find_coercion_lub: was able to coerce from previous type {:?} to new type {:?}",
-                        prev_ty, new_ty,
+                        "coercion::try_find_coercion_lub: was able to coerce from new type {:?} to previous type {:?} ({:?})",
+                        new_ty, prev_ty, target
                     );
                     return Ok(target);
                 }
@@ -1162,15 +1204,15 @@
                 }
             }
             Ok(ok) => {
-                debug!(
-                    "coercion::try_find_coercion_lub: was able to coerce previous type {:?} to new type {:?}",
-                    prev_ty, new_ty,
-                );
                 let (adjustments, target) = self.register_infer_ok_obligations(ok);
                 for expr in exprs {
                     let expr = expr.as_coercion_site();
                     self.apply_adjustments(expr, adjustments.clone());
                 }
+                debug!(
+                    "coercion::try_find_coercion_lub: was able to coerce previous type {:?} to new type {:?} ({:?})",
+                    prev_ty, new_ty, target
+                );
                 Ok(target)
             }
         }
@@ -1323,7 +1365,7 @@
     /// is a forced-unit case, and hence `expression_ty` must be
     /// `Nil`.
     #[instrument(skip(self, fcx, augment_error, label_expression_as_expected), level = "debug")]
-    crate fn coerce_inner<'a>(
+    pub(crate) fn coerce_inner<'a>(
         &mut self,
         fcx: &FnCtxt<'a, 'tcx>,
         cause: &ObligationCause<'tcx>,
@@ -1402,6 +1444,7 @@
                 })
         };
 
+        debug!(?result);
         match result {
             Ok(v) => {
                 self.final_ty = Some(v);
@@ -1457,7 +1500,8 @@
                             coercion_error.clone(),
                             fcx,
                             parent_id,
-                            expression.map(|expr| (expr, blk_id)),
+                            expression,
+                            Some(blk_id),
                         );
                         if !fcx.tcx.features().unsized_locals {
                             unsized_return = self.is_return_ty_unsized(fcx, blk_id);
@@ -1471,6 +1515,7 @@
                             coercion_error.clone(),
                             fcx,
                             id,
+                            expression,
                             None,
                         );
                         if !fcx.tcx.features().unsized_locals {
@@ -1492,7 +1537,10 @@
                     augment_error(&mut err);
                 }
 
-                if let Some(expr) = expression {
+                let is_insufficiently_polymorphic =
+                    matches!(coercion_error, TypeError::RegionsInsufficientlyPolymorphic(..));
+
+                if !is_insufficiently_polymorphic && let Some(expr) = expression {
                     fcx.emit_coerce_suggestions(
                         &mut err,
                         expr,
@@ -1518,21 +1566,28 @@
         ty_err: TypeError<'tcx>,
         fcx: &FnCtxt<'a, 'tcx>,
         id: hir::HirId,
-        expression: Option<(&'tcx hir::Expr<'tcx>, hir::HirId)>,
+        expression: Option<&'tcx hir::Expr<'tcx>>,
+        blk_id: Option<hir::HirId>,
     ) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
         let mut err = fcx.report_mismatched_types(cause, expected, found, ty_err);
 
         let mut pointing_at_return_type = false;
         let mut fn_output = None;
 
+        let parent_id = fcx.tcx.hir().get_parent_node(id);
+        let parent = fcx.tcx.hir().get(parent_id);
+        if let Some(expr) = expression
+            && let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Closure { body, .. }, .. }) = parent
+            && !matches!(fcx.tcx.hir().body(*body).value.kind, hir::ExprKind::Block(..))
+        {
+            fcx.suggest_missing_semicolon(&mut err, expr, expected, true);
+        }
         // Verify that this is a tail expression of a function, otherwise the
         // label pointing out the cause for the type coercion will be wrong
         // as prior return coercions would not be relevant (#57664).
-        let parent_id = fcx.tcx.hir().get_parent_node(id);
-        let fn_decl = if let Some((expr, blk_id)) = expression {
+        let fn_decl = if let (Some(expr), Some(blk_id)) = (expression, blk_id) {
             pointing_at_return_type =
                 fcx.suggest_mismatched_types_on_tail(&mut err, expr, expected, found, blk_id);
-            let parent = fcx.tcx.hir().get(parent_id);
             if let (Some(cond_expr), true, false) = (
                 fcx.tcx.hir().get_if_cause(expr.hir_id),
                 expected.is_unit(),
@@ -1561,7 +1616,7 @@
         };
 
         if let Some((fn_decl, can_suggest)) = fn_decl {
-            if expression.is_none() {
+            if blk_id.is_none() {
                 pointing_at_return_type |= fcx.suggest_missing_return_type(
                     &mut err,
                     &fn_decl,
@@ -1579,8 +1634,8 @@
         let parent_id = fcx.tcx.hir().get_parent_item(id);
         let parent_item = fcx.tcx.hir().get_by_def_id(parent_id);
 
-        if let (Some((expr, _)), Some((fn_decl, _, _))) =
-            (expression, fcx.get_node_fn_decl(parent_item))
+        if let (Some(expr), Some(_), Some((fn_decl, _, _))) =
+            (expression, blk_id, fcx.get_node_fn_decl(parent_item))
         {
             fcx.suggest_missing_break_or_return_expr(
                 &mut err,
diff --git a/compiler/rustc_typeck/src/check/compare_method.rs b/compiler/rustc_typeck/src/check/compare_method.rs
index b857679..95c82a7 100644
--- a/compiler/rustc_typeck/src/check/compare_method.rs
+++ b/compiler/rustc_typeck/src/check/compare_method.rs
@@ -28,7 +28,7 @@
 /// - `impl_m_span`: span to use for reporting errors
 /// - `trait_m`: the method in the trait
 /// - `impl_trait_ref`: the TraitRef corresponding to the trait implementation
-crate fn compare_impl_method<'tcx>(
+pub(crate) fn compare_impl_method<'tcx>(
     tcx: TyCtxt<'tcx>,
     impl_m: &ty::AssocItem,
     impl_m_span: Span,
@@ -255,7 +255,7 @@
 
         let mut wf_tys = FxHashSet::default();
 
-        let (impl_sig, _) = infcx.replace_bound_vars_with_fresh_vars(
+        let impl_sig = infcx.replace_bound_vars_with_fresh_vars(
             impl_m_span,
             infer::HigherRankedType,
             tcx.fn_sig(impl_m.def_id),
@@ -354,7 +354,7 @@
                                         diag.span_suggestion_verbose(sp, msg, sugg, ap);
                                     }
                                     hir::FnRetTy::Return(hir_ty) => {
-                                        let sugg = trait_sig.output().to_string();
+                                        let sugg = trait_sig.output();
                                         diag.span_suggestion(hir_ty.span, msg, sugg, ap);
                                     }
                                 };
@@ -365,7 +365,7 @@
                         diag.span_suggestion(
                             impl_err_span,
                             "change the parameter type to match the trait",
-                            trait_ty.to_string(),
+                            trait_ty,
                             Applicability::MachineApplicable,
                         );
                     }
@@ -628,24 +628,40 @@
     let mut err_occurred = None;
     for (kind, trait_count, impl_count) in matchings {
         if impl_count != trait_count {
+            let arg_spans = |kind: ty::AssocKind, generics: &hir::Generics<'_>| {
+                let mut spans = generics
+                    .params
+                    .iter()
+                    .filter(|p| match p.kind {
+                        hir::GenericParamKind::Lifetime {
+                            kind: hir::LifetimeParamKind::Elided,
+                        } => {
+                            // A fn can have an arbitrary number of extra elided lifetimes for the
+                            // same signature.
+                            !matches!(kind, ty::AssocKind::Fn)
+                        }
+                        _ => true,
+                    })
+                    .map(|p| p.span)
+                    .collect::<Vec<Span>>();
+                if spans.is_empty() {
+                    spans = vec![generics.span]
+                }
+                spans
+            };
             let (trait_spans, impl_trait_spans) = if let Some(def_id) = trait_.def_id.as_local() {
                 let trait_item = tcx.hir().expect_trait_item(def_id);
-                if trait_item.generics.params.is_empty() {
-                    (Some(vec![trait_item.generics.span]), vec![])
-                } else {
-                    let arg_spans: Vec<Span> =
-                        trait_item.generics.params.iter().map(|p| p.span).collect();
-                    let impl_trait_spans: Vec<Span> = trait_item
-                        .generics
-                        .params
-                        .iter()
-                        .filter_map(|p| match p.kind {
-                            GenericParamKind::Type { synthetic: true, .. } => Some(p.span),
-                            _ => None,
-                        })
-                        .collect();
-                    (Some(arg_spans), impl_trait_spans)
-                }
+                let arg_spans: Vec<Span> = arg_spans(trait_.kind, trait_item.generics);
+                let impl_trait_spans: Vec<Span> = trait_item
+                    .generics
+                    .params
+                    .iter()
+                    .filter_map(|p| match p.kind {
+                        GenericParamKind::Type { synthetic: true, .. } => Some(p.span),
+                        _ => None,
+                    })
+                    .collect();
+                (Some(arg_spans), impl_trait_spans)
             } else {
                 (trait_span.map(|s| vec![s]), vec![])
             };
@@ -660,8 +676,8 @@
                     _ => None,
                 })
                 .collect();
-            let spans = impl_item.generics.spans();
-            let span = spans.primary_span();
+            let spans = arg_spans(impl_.kind, impl_item.generics);
+            let span = spans.first().copied();
 
             let mut err = tcx.sess.struct_span_err_with_code(
                 spans,
@@ -1038,7 +1054,7 @@
     Ok(())
 }
 
-crate fn compare_const_impl<'tcx>(
+pub(crate) fn compare_const_impl<'tcx>(
     tcx: TyCtxt<'tcx>,
     impl_c: &ty::AssocItem,
     impl_c_span: Span,
@@ -1144,7 +1160,7 @@
     });
 }
 
-crate fn compare_ty_impl<'tcx>(
+pub(crate) fn compare_ty_impl<'tcx>(
     tcx: TyCtxt<'tcx>,
     impl_ty: &ty::AssocItem,
     impl_ty_span: Span,
@@ -1363,7 +1379,7 @@
             bound_vars.push(bound_var);
             tcx.mk_const(ty::ConstS {
                 ty: tcx.type_of(param.def_id),
-                val: ty::ConstKind::Bound(
+                kind: ty::ConstKind::Bound(
                     ty::INNERMOST,
                     ty::BoundVar::from_usize(bound_vars.len() - 1),
                 ),
diff --git a/compiler/rustc_typeck/src/check/demand.rs b/compiler/rustc_typeck/src/check/demand.rs
index ae4cebe..961bbc4 100644
--- a/compiler/rustc_typeck/src/check/demand.rs
+++ b/compiler/rustc_typeck/src/check/demand.rs
@@ -12,7 +12,7 @@
 use rustc_middle::ty::adjustment::AllowTwoPhase;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
 use rustc_middle::ty::print::with_no_trimmed_paths;
-use rustc_middle::ty::{self, AssocItem, Ty, TypeAndMut};
+use rustc_middle::ty::{self, Article, AssocItem, Ty, TypeAndMut};
 use rustc_span::symbol::{sym, Symbol};
 use rustc_span::{BytePos, Span};
 
@@ -129,6 +129,7 @@
     ///
     /// N.B., this code relies on `self.diverges` to be accurate. In particular, assignments to `!`
     /// will be permitted if the diverges flag is currently "always".
+    #[tracing::instrument(level = "debug", skip(self, expr, expected_ty_expr, allow_two_phase))]
     pub fn demand_coerce_diag(
         &self,
         expr: &hir::Expr<'tcx>,
@@ -150,7 +151,22 @@
         let expr_ty = self.resolve_vars_with_obligations(checked_ty);
         let mut err = self.report_mismatched_types(&cause, expected, expr_ty, e.clone());
 
-        self.emit_coerce_suggestions(&mut err, expr, expr_ty, expected, expected_ty_expr, Some(e));
+        let is_insufficiently_polymorphic =
+            matches!(e, TypeError::RegionsInsufficientlyPolymorphic(..));
+
+        // FIXME(#73154): For now, we do leak check when coercing function
+        // pointers in typeck, instead of only during borrowck. This can lead
+        // to these `RegionsInsufficientlyPolymorphic` errors that aren't helpful.
+        if !is_insufficiently_polymorphic {
+            self.emit_coerce_suggestions(
+                &mut err,
+                expr,
+                expr_ty,
+                expected,
+                expected_ty_expr,
+                Some(e),
+            );
+        }
 
         (expected, Some(err))
     }
@@ -467,7 +483,7 @@
         let param_parent = self.tcx.hir().get_parent_node(*param_hir_id);
         let Some(Node::Expr(hir::Expr {
             hir_id: expr_hir_id,
-            kind: hir::ExprKind::Closure(_, closure_fn_decl, ..),
+            kind: hir::ExprKind::Closure { fn_decl: closure_fn_decl, .. },
             ..
         })) = self.tcx.hir().find(param_parent) else {
             return None;
@@ -503,7 +519,7 @@
         }
     }
 
-    crate fn maybe_get_struct_pattern_shorthand_field(
+    pub(crate) fn maybe_get_struct_pattern_shorthand_field(
         &self,
         expr: &hir::Expr<'_>,
     ) -> Option<Symbol> {
@@ -539,7 +555,10 @@
     }
 
     /// If the given `HirId` corresponds to a block with a trailing expression, return that expression
-    crate fn maybe_get_block_expr(&self, expr: &hir::Expr<'tcx>) -> Option<&'tcx hir::Expr<'tcx>> {
+    pub(crate) fn maybe_get_block_expr(
+        &self,
+        expr: &hir::Expr<'tcx>,
+    ) -> Option<&'tcx hir::Expr<'tcx>> {
         match expr {
             hir::Expr { kind: hir::ExprKind::Block(block, ..), .. } => block.expr,
             _ => None,
@@ -547,7 +566,7 @@
     }
 
     /// Returns whether the given expression is an `else if`.
-    crate fn is_else_if_block(&self, expr: &hir::Expr<'_>) -> bool {
+    pub(crate) fn is_else_if_block(&self, expr: &hir::Expr<'_>) -> bool {
         if let hir::ExprKind::If(..) = expr.kind {
             let parent_id = self.tcx.hir().get_parent_node(expr.hir_id);
             if let Some(Node::Expr(hir::Expr {
@@ -696,28 +715,13 @@
                         };
 
                         if let Some(hir::Node::Expr(hir::Expr {
-                            kind: hir::ExprKind::Assign(left_expr, ..),
+                            kind: hir::ExprKind::Assign(..),
                             ..
                         })) = self.tcx.hir().find(self.tcx.hir().get_parent_node(expr.hir_id))
                         {
                             if mutability == hir::Mutability::Mut {
-                                // Found the following case:
-                                // fn foo(opt: &mut Option<String>){ opt = None }
-                                //                                   ---   ^^^^
-                                //                                   |     |
-                                //    consider dereferencing here: `*opt`  |
-                                // expected mutable reference, found enum `Option`
-                                if sm.span_to_snippet(left_expr.span).is_ok() {
-                                    return Some((
-                                        left_expr.span.shrink_to_lo(),
-                                        "consider dereferencing here to assign to the mutable \
-                                         borrowed piece of memory"
-                                            .to_string(),
-                                        "*".to_string(),
-                                        Applicability::MachineApplicable,
-                                        true,
-                                    ));
-                                }
+                                // Suppressing this diagnostic, we'll properly print it in `check_expr_assign`
+                                return None;
                             }
                         }
 
diff --git a/compiler/rustc_typeck/src/check/dropck.rs b/compiler/rustc_typeck/src/check/dropck.rs
index 9caa4a4..3070643 100644
--- a/compiler/rustc_typeck/src/check/dropck.rs
+++ b/compiler/rustc_typeck/src/check/dropck.rs
@@ -2,17 +2,14 @@
 use crate::hir;
 use crate::hir::def_id::{DefId, LocalDefId};
 use rustc_errors::{struct_span_err, ErrorGuaranteed};
-use rustc_infer::infer::outlives::env::OutlivesEnvironment;
-use rustc_infer::infer::{InferOk, RegionckMode, TyCtxtInferExt};
-use rustc_infer::traits::TraitEngineExt as _;
 use rustc_middle::ty::error::TypeError;
 use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation};
-use rustc_middle::ty::subst::{Subst, SubstsRef};
-use rustc_middle::ty::{self, EarlyBinder, Predicate, Ty, TyCtxt};
+use rustc_middle::ty::subst::SubstsRef;
+use rustc_middle::ty::util::IgnoreRegions;
+use rustc_middle::ty::{self, Predicate, Ty, TyCtxt};
 use rustc_span::Span;
-use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
 use rustc_trait_selection::traits::query::dropck_outlives::AtExt;
-use rustc_trait_selection::traits::{ObligationCause, TraitEngine, TraitEngineExt};
+use rustc_trait_selection::traits::ObligationCause;
 
 /// This function confirms that the `Drop` implementation identified by
 /// `drop_impl_did` is not any more specialized than the type it is
@@ -39,8 +36,8 @@
             ensure_drop_params_and_item_params_correspond(
                 tcx,
                 drop_impl_did.expect_local(),
-                dtor_self_type,
                 adt_def.did(),
+                self_to_impl_substs,
             )?;
 
             ensure_drop_predicates_are_implied_by_item_defn(
@@ -67,75 +64,34 @@
 fn ensure_drop_params_and_item_params_correspond<'tcx>(
     tcx: TyCtxt<'tcx>,
     drop_impl_did: LocalDefId,
-    drop_impl_ty: Ty<'tcx>,
     self_type_did: DefId,
+    drop_impl_substs: SubstsRef<'tcx>,
 ) -> Result<(), ErrorGuaranteed> {
-    let drop_impl_hir_id = tcx.hir().local_def_id_to_hir_id(drop_impl_did);
+    let Err(arg) = tcx.uses_unique_generic_params(drop_impl_substs, IgnoreRegions::No) else {
+        return Ok(())
+    };
 
-    // check that the impl type can be made to match the trait type.
-
-    tcx.infer_ctxt().enter(|ref infcx| {
-        let impl_param_env = tcx.param_env(self_type_did);
-        let tcx = infcx.tcx;
-        let mut fulfillment_cx = <dyn TraitEngine<'_>>::new(tcx);
-
-        let named_type = tcx.type_of(self_type_did);
-
-        let drop_impl_span = tcx.def_span(drop_impl_did);
-        let fresh_impl_substs =
-            infcx.fresh_substs_for_item(drop_impl_span, drop_impl_did.to_def_id());
-        let fresh_impl_self_ty = EarlyBinder(drop_impl_ty).subst(tcx, fresh_impl_substs);
-
-        let cause = &ObligationCause::misc(drop_impl_span, drop_impl_hir_id);
-        match infcx.at(cause, impl_param_env).eq(named_type, fresh_impl_self_ty) {
-            Ok(InferOk { obligations, .. }) => {
-                fulfillment_cx.register_predicate_obligations(infcx, obligations);
-            }
-            Err(_) => {
-                let item_span = tcx.def_span(self_type_did);
-                let self_descr = tcx.def_kind(self_type_did).descr(self_type_did);
-                let reported = struct_span_err!(
-                    tcx.sess,
-                    drop_impl_span,
-                    E0366,
-                    "`Drop` impls cannot be specialized"
-                )
-                .span_note(
-                    item_span,
-                    &format!(
-                        "use the same sequence of generic type, lifetime and const parameters \
-                        as the {self_descr} definition",
-                    ),
-                )
-                .emit();
-                return Err(reported);
-            }
+    let drop_impl_span = tcx.def_span(drop_impl_did);
+    let item_span = tcx.def_span(self_type_did);
+    let self_descr = tcx.def_kind(self_type_did).descr(self_type_did);
+    let mut err =
+        struct_span_err!(tcx.sess, drop_impl_span, E0366, "`Drop` impls cannot be specialized");
+    match arg {
+        ty::util::NotUniqueParam::DuplicateParam(arg) => {
+            err.note(&format!("`{arg}` is mentioned multiple times"))
         }
-
-        let errors = fulfillment_cx.select_all_or_error(&infcx);
-        if !errors.is_empty() {
-            // this could be reached when we get lazy normalization
-            let reported = infcx.report_fulfillment_errors(&errors, None, false);
-            return Err(reported);
+        ty::util::NotUniqueParam::NotParam(arg) => {
+            err.note(&format!("`{arg}` is not a generic parameter"))
         }
-
-        // 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
-        // allow region solving to take any `a: 'b` relations on the
-        // impl into account. But I could not create a test case where
-        // it did the wrong thing, so I chose to preserve existing
-        // behavior, since it ought to be simply more
-        // conservative. -nmatsakis
-        let outlives_env = OutlivesEnvironment::new(ty::ParamEnv::empty());
-
-        infcx.resolve_regions_and_report_errors(
-            drop_impl_did.to_def_id(),
-            &outlives_env,
-            RegionckMode::default(),
-        );
-        Ok(())
-    })
+    };
+    err.span_note(
+        item_span,
+        &format!(
+            "use the same sequence of generic lifetime, type and const parameters \
+                     as the {self_descr} definition",
+        ),
+    );
+    Err(err.emit())
 }
 
 /// Confirms that every predicate imposed by dtor_predicates is
@@ -275,7 +231,7 @@
 /// This function is not only checking that the dropck obligations are met for
 /// the given type, but it's also currently preventing non-regular recursion in
 /// types from causing stack overflows (dropck_no_diverge_on_nonregular_*.rs).
-crate fn check_drop_obligations<'a, 'tcx>(
+pub(crate) fn check_drop_obligations<'a, 'tcx>(
     rcx: &mut RegionCtxt<'a, 'tcx>,
     ty: Ty<'tcx>,
     span: Span,
@@ -292,7 +248,7 @@
 // This is an implementation of the TypeRelation trait with the
 // aim of simply comparing for equality (without side-effects).
 // It is not intended to be used anywhere else other than here.
-crate struct SimpleEqRelation<'tcx> {
+pub(crate) struct SimpleEqRelation<'tcx> {
     tcx: TyCtxt<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
 }
diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs
index 427b22d..b4476d5 100644
--- a/compiler/rustc_typeck/src/check/expr.rs
+++ b/compiler/rustc_typeck/src/check/expr.rs
@@ -26,10 +26,10 @@
 use rustc_ast as ast;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::stack::ensure_sufficient_stack;
-use rustc_errors::Diagnostic;
-use rustc_errors::EmissionGuarantee;
-use rustc_errors::ErrorGuaranteed;
-use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, DiagnosticId};
+use rustc_errors::{
+    pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, DiagnosticId,
+    EmissionGuarantee, ErrorGuaranteed,
+};
 use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, DefKind, Res};
 use rustc_hir::def_id::DefId;
@@ -39,10 +39,10 @@
 use rustc_infer::infer;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_infer::infer::InferOk;
+use rustc_infer::traits::ObligationCause;
 use rustc_middle::middle::stability;
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase};
-use rustc_middle::ty::error::ExpectedFound;
-use rustc_middle::ty::error::TypeError::{FieldMisMatch, Sorts};
+use rustc_middle::ty::error::TypeError::FieldMisMatch;
 use rustc_middle::ty::subst::SubstsRef;
 use rustc_middle::ty::{self, AdtKind, DefIdTree, Ty, TypeFoldable};
 use rustc_session::parse::feature_err;
@@ -51,6 +51,8 @@
 use rustc_span::source_map::Span;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{BytePos, Pos};
+use rustc_target::spec::abi::Abi::RustIntrinsic;
+use rustc_trait_selection::infer::InferCtxtExt;
 use rustc_trait_selection::traits::{self, ObligationCauseCode};
 
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
@@ -63,7 +65,7 @@
         &self,
         expr: &'tcx hir::Expr<'tcx>,
         expected: Ty<'tcx>,
-        extend_err: impl Fn(&mut Diagnostic),
+        extend_err: impl FnMut(&mut Diagnostic),
     ) -> Ty<'tcx> {
         self.check_expr_meets_expectation_or_error(expr, ExpectHasType(expected), extend_err)
     }
@@ -72,7 +74,7 @@
         &self,
         expr: &'tcx hir::Expr<'tcx>,
         expected: Expectation<'tcx>,
-        extend_err: impl Fn(&mut Diagnostic),
+        mut extend_err: impl FnMut(&mut Diagnostic),
     ) -> Ty<'tcx> {
         let expected_ty = expected.to_option(&self).unwrap_or(self.tcx.types.bool);
         let mut ty = self.check_expr_with_expectation(expr, expected);
@@ -293,7 +295,11 @@
                 self.check_lang_item_path(lang_item, expr, hir_id)
             }
             ExprKind::Path(ref qpath) => self.check_expr_path(qpath, expr, &[]),
-            ExprKind::InlineAsm(asm) => self.check_expr_asm(asm),
+            ExprKind::InlineAsm(asm) => {
+                // We defer some asm checks as we may not have resolved the input and output types yet (they may still be infer vars).
+                self.deferred_asm_checks.borrow_mut().push((asm, expr.hir_id));
+                self.check_expr_asm(asm)
+            }
             ExprKind::Break(destination, ref expr_opt) => {
                 self.check_expr_break(destination, expr_opt.as_deref(), expr)
             }
@@ -313,8 +319,8 @@
             ExprKind::Match(discrim, arms, match_src) => {
                 self.check_match(expr, &discrim, arms, expected, match_src)
             }
-            ExprKind::Closure(capture, decl, body_id, _, gen) => {
-                self.check_expr_closure(expr, capture, &decl, body_id, gen, expected)
+            ExprKind::Closure { capture_clause, fn_decl, body, movability, .. } => {
+                self.check_expr_closure(expr, capture_clause, &fn_decl, body, movability, expected)
             }
             ExprKind::Block(body, _) => self.check_block_with_expected(&body, expected),
             ExprKind::Call(callee, args) => self.check_call(expr, &callee, args, expected),
@@ -529,8 +535,17 @@
             _ => self.instantiate_value_path(segs, opt_ty, res, expr.span, expr.hir_id).0,
         };
 
-        if let ty::FnDef(..) = ty.kind() {
+        if let ty::FnDef(did, ..) = *ty.kind() {
             let fn_sig = ty.fn_sig(tcx);
+            if tcx.fn_sig(did).abi() == RustIntrinsic && tcx.item_name(did) == sym::transmute {
+                let from = fn_sig.inputs().skip_binder()[0];
+                let to = fn_sig.output().skip_binder();
+                // We defer the transmute to the end of typeck, once all inference vars have
+                // been resolved or we errored. This is important as we can only check transmute
+                // on concrete types, but the output type may not be known yet (it would only
+                // be known if explicitly specified via turbofish).
+                self.deferred_transmute_checks.borrow_mut().push((from, to, expr.span));
+            }
             if !tcx.features().unsized_fn_params {
                 // We want to remove some Sized bounds from std functions,
                 // but don't want to expose the removal to stable Rust.
@@ -546,13 +561,11 @@
                     // placeholder lifetimes with probing, we just replace higher lifetimes
                     // with fresh vars.
                     let span = args.get(i).map(|a| a.span).unwrap_or(expr.span);
-                    let input = self
-                        .replace_bound_vars_with_fresh_vars(
-                            span,
-                            infer::LateBoundRegionConversionTime::FnCall,
-                            fn_sig.input(i),
-                        )
-                        .0;
+                    let input = self.replace_bound_vars_with_fresh_vars(
+                        span,
+                        infer::LateBoundRegionConversionTime::FnCall,
+                        fn_sig.input(i),
+                    );
                     self.require_type_is_sized_deferred(
                         input,
                         span,
@@ -566,13 +579,11 @@
             // Also, as we just want to check sizedness, instead of introducing
             // placeholder lifetimes with probing, we just replace higher lifetimes
             // with fresh vars.
-            let output = self
-                .replace_bound_vars_with_fresh_vars(
-                    expr.span,
-                    infer::LateBoundRegionConversionTime::FnCall,
-                    fn_sig.output(),
-                )
-                .0;
+            let output = self.replace_bound_vars_with_fresh_vars(
+                expr.span,
+                infer::LateBoundRegionConversionTime::FnCall,
+                fn_sig.output(),
+            );
             self.require_type_is_sized_deferred(output, expr.span, traits::SizedReturnType);
         }
 
@@ -829,6 +840,37 @@
             return_expr,
             return_expr_ty,
         );
+
+        if self.return_type_has_opaque {
+            // Point any obligations that were registered due to opaque type
+            // inference at the return expression.
+            self.select_obligations_where_possible(false, |errors| {
+                self.point_at_return_for_opaque_ty_error(errors, span, return_expr_ty);
+            });
+        }
+    }
+
+    fn point_at_return_for_opaque_ty_error(
+        &self,
+        errors: &mut Vec<traits::FulfillmentError<'tcx>>,
+        span: Span,
+        return_expr_ty: Ty<'tcx>,
+    ) {
+        // Don't point at the whole block if it's empty
+        if span == self.tcx.hir().span(self.body_id) {
+            return;
+        }
+        for err in errors {
+            let cause = &mut err.obligation.cause;
+            if let ObligationCauseCode::OpaqueReturnType(None) = cause.code() {
+                let new_cause = ObligationCause::new(
+                    cause.span,
+                    cause.body_id,
+                    ObligationCauseCode::OpaqueReturnType(Some((return_expr_ty, span))),
+                );
+                *cause = new_cause;
+            }
+        }
     }
 
     pub(crate) fn check_lhs_assignable(
@@ -836,6 +878,7 @@
         lhs: &'tcx hir::Expr<'tcx>,
         err_code: &'static str,
         op_span: Span,
+        adjust_err: impl FnOnce(&mut DiagnosticBuilder<'tcx, ErrorGuaranteed>),
     ) {
         if lhs.is_syntactic_place_expr() {
             return;
@@ -853,11 +896,13 @@
             err.span_suggestion_verbose(
                 expr.span.shrink_to_lo(),
                 "you might have meant to use pattern destructuring",
-                "let ".to_string(),
+                "let ",
                 Applicability::MachineApplicable,
             );
         });
 
+        adjust_err(&mut err);
+
         err.emit();
     }
 
@@ -1017,7 +1062,10 @@
             } else {
                 (Applicability::MaybeIncorrect, false)
             };
-            if !lhs.is_syntactic_place_expr() && !matches!(lhs.kind, hir::ExprKind::Lit(_)) {
+            if !lhs.is_syntactic_place_expr()
+                && lhs.is_approximately_pattern()
+                && !matches!(lhs.kind, hir::ExprKind::Lit(_))
+            {
                 // Do not suggest `if let x = y` as `==` is way more likely to be the intention.
                 let hir = self.tcx.hir();
                 if let hir::Node::Expr(hir::Expr { kind: ExprKind::If { .. }, .. }) =
@@ -1026,7 +1074,7 @@
                     err.span_suggestion_verbose(
                         expr.span.shrink_to_lo(),
                         "you might have meant to use pattern matching",
-                        "let ".to_string(),
+                        "let ",
                         applicability,
                     );
                 };
@@ -1035,7 +1083,7 @@
                 err.span_suggestion_verbose(
                     span,
                     "you might have meant to compare for equality",
-                    "==".to_string(),
+                    "==",
                     applicability,
                 );
             }
@@ -1050,10 +1098,47 @@
             return self.tcx.ty_error();
         }
 
-        self.check_lhs_assignable(lhs, "E0070", span);
-
         let lhs_ty = self.check_expr_with_needs(&lhs, Needs::MutPlace);
-        let rhs_ty = self.check_expr_coercable_to_type(&rhs, lhs_ty, Some(lhs));
+
+        let suggest_deref_binop = |err: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>,
+                                   rhs_ty: Ty<'tcx>| {
+            if let Some(lhs_deref_ty) = self.deref_once_mutably_for_diagnostic(lhs_ty) {
+                // Can only assign if the type is sized, so if `DerefMut` yields a type that is
+                // unsized, do not suggest dereferencing it.
+                let lhs_deref_ty_is_sized = self
+                    .infcx
+                    .type_implements_trait(
+                        self.tcx.lang_items().sized_trait().unwrap(),
+                        lhs_deref_ty,
+                        ty::List::empty(),
+                        self.param_env,
+                    )
+                    .may_apply();
+                if lhs_deref_ty_is_sized && self.can_coerce(rhs_ty, lhs_deref_ty) {
+                    err.span_suggestion_verbose(
+                        lhs.span.shrink_to_lo(),
+                        "consider dereferencing here to assign to the mutably borrowed value",
+                        "*",
+                        Applicability::MachineApplicable,
+                    );
+                }
+            }
+        };
+
+        self.check_lhs_assignable(lhs, "E0070", span, |err| {
+            let rhs_ty = self.check_expr(&rhs);
+            suggest_deref_binop(err, rhs_ty);
+        });
+
+        // This is (basically) inlined `check_expr_coercable_to_type`, but we want
+        // to suggest an additional fixup here in `suggest_deref_binop`.
+        let rhs_ty = self.check_expr_with_hint(&rhs, lhs_ty);
+        if let (_, Some(mut diag)) =
+            self.demand_coerce_diag(rhs, rhs_ty, lhs_ty, Some(lhs), AllowTwoPhase::No)
+        {
+            suggest_deref_binop(&mut diag, rhs_ty);
+            diag.emit();
+        }
 
         self.require_type_is_sized(lhs_ty, lhs.span, traits::AssignmentLhsSized);
 
@@ -1064,7 +1149,7 @@
         }
     }
 
-    fn check_expr_let(&self, let_expr: &'tcx hir::Let<'tcx>) -> Ty<'tcx> {
+    pub(super) fn check_expr_let(&self, let_expr: &'tcx hir::Let<'tcx>) -> Ty<'tcx> {
         // for let statements, this is done in check_stmt
         let init = let_expr.init;
         self.warn_if_unreachable(init.hir_id, init.span, "block in `let` expression");
@@ -1416,18 +1501,20 @@
     ) {
         let tcx = self.tcx;
 
-        let adt_ty_hint = self
-            .expected_inputs_for_expected_output(span, expected, adt_ty, &[adt_ty])
-            .get(0)
-            .cloned()
-            .unwrap_or(adt_ty);
+        let expected_inputs =
+            self.expected_inputs_for_expected_output(span, expected, adt_ty, &[adt_ty]);
+        let adt_ty_hint = if let Some(expected_inputs) = expected_inputs {
+            expected_inputs.get(0).cloned().unwrap_or(adt_ty)
+        } else {
+            adt_ty
+        };
         // re-link the regions that EIfEO can erase.
         self.demand_eqtype(span, adt_ty_hint, adt_ty);
 
-        let (substs, adt_kind, kind_name) = match adt_ty.kind() {
-            ty::Adt(adt, substs) => (substs, adt.adt_kind(), adt.variant_descr()),
-            _ => span_bug!(span, "non-ADT passed to check_expr_struct_fields"),
+        let ty::Adt(adt, substs) = adt_ty.kind() else {
+            span_bug!(span, "non-ADT passed to check_expr_struct_fields");
         };
+        let adt_kind = adt.adt_kind();
 
         let mut remaining_fields = variant
             .fields
@@ -1465,7 +1552,12 @@
                     });
                 } else {
                     self.report_unknown_field(
-                        adt_ty, variant, field, ast_fields, kind_name, expr_span,
+                        adt_ty,
+                        variant,
+                        field,
+                        ast_fields,
+                        adt.variant_descr(),
+                        expr_span,
                     );
                 }
 
@@ -1478,7 +1570,7 @@
         }
 
         // Make sure the programmer specified correct number of fields.
-        if kind_name == "union" {
+        if adt_kind == AdtKind::Union {
             if ast_fields.len() != 1 {
                 struct_span_err!(
                     tcx.sess,
@@ -1501,67 +1593,78 @@
             // FIXME: We are currently creating two branches here in order to maintain
             // consistency. But they should be merged as much as possible.
             let fru_tys = if self.tcx.features().type_changing_struct_update {
-                let base_ty = self.check_expr(base_expr);
-                match adt_ty.kind() {
-                    ty::Adt(adt, substs) if adt.is_struct() => {
-                        match base_ty.kind() {
-                            ty::Adt(base_adt, base_subs) if adt == base_adt => {
-                                variant
-                                    .fields
-                                    .iter()
-                                    .map(|f| {
-                                        let fru_ty = self.normalize_associated_types_in(
-                                            expr_span,
-                                            self.field_ty(base_expr.span, f, base_subs),
-                                        );
-                                        let ident = self
-                                            .tcx
-                                            .adjust_ident(f.ident(self.tcx), variant.def_id);
-                                        if let Some(_) = remaining_fields.remove(&ident) {
-                                            let target_ty =
-                                                self.field_ty(base_expr.span, f, substs);
-                                            let cause = self.misc(base_expr.span);
-                                            match self
-                                                .at(&cause, self.param_env)
-                                                .sup(target_ty, fru_ty)
-                                            {
-                                                Ok(InferOk { obligations, value: () }) => {
-                                                    self.register_predicates(obligations)
-                                                }
-                                                // FIXME: Need better diagnostics for `FieldMisMatch` error
-                                                Err(_) => {
-                                                    self.report_mismatched_types(
-                                                        &cause,
-                                                        target_ty,
-                                                        fru_ty,
-                                                        FieldMisMatch(variant.name, ident.name),
-                                                    )
-                                                    .emit();
-                                                }
-                                            }
-                                        }
-                                        fru_ty
-                                    })
-                                    .collect()
+                if adt.is_struct() {
+                    // Make some fresh substitutions for our ADT type.
+                    let fresh_substs = self.fresh_substs_for_item(base_expr.span, adt.did());
+                    // We do subtyping on the FRU fields first, so we can
+                    // learn exactly what types we expect the base expr
+                    // needs constrained to be compatible with the struct
+                    // type we expect from the expectation value.
+                    let fru_tys = variant
+                        .fields
+                        .iter()
+                        .map(|f| {
+                            let fru_ty = self.normalize_associated_types_in(
+                                expr_span,
+                                self.field_ty(base_expr.span, f, fresh_substs),
+                            );
+                            let ident = self.tcx.adjust_ident(f.ident(self.tcx), variant.def_id);
+                            if let Some(_) = remaining_fields.remove(&ident) {
+                                let target_ty = self.field_ty(base_expr.span, f, substs);
+                                let cause = self.misc(base_expr.span);
+                                match self.at(&cause, self.param_env).sup(target_ty, fru_ty) {
+                                    Ok(InferOk { obligations, value: () }) => {
+                                        self.register_predicates(obligations)
+                                    }
+                                    Err(_) => {
+                                        // This should never happen, since we're just subtyping the
+                                        // remaining_fields, but it's fine to emit this, I guess.
+                                        self.report_mismatched_types(
+                                            &cause,
+                                            target_ty,
+                                            fru_ty,
+                                            FieldMisMatch(variant.name, ident.name),
+                                        )
+                                        .emit();
+                                    }
+                                }
                             }
-                            _ => {
-                                self.report_mismatched_types(
-                                    &self.misc(base_expr.span),
-                                    adt_ty,
-                                    base_ty,
-                                    Sorts(ExpectedFound::new(true, adt_ty, base_ty)),
-                                )
-                                .emit();
-                                return;
-                            }
-                        }
-                    }
-                    _ => {
-                        self.tcx
-                            .sess
-                            .emit_err(FunctionalRecordUpdateOnNonStruct { span: base_expr.span });
-                        return;
-                    }
+                            self.resolve_vars_if_possible(fru_ty)
+                        })
+                        .collect();
+                    // The use of fresh substs that we have subtyped against
+                    // our base ADT type's fields allows us to guide inference
+                    // along so that, e.g.
+                    // ```
+                    // MyStruct<'a, F1, F2, const C: usize> {
+                    //     f: F1,
+                    //     // Other fields that reference `'a`, `F2`, and `C`
+                    // }
+                    //
+                    // let x = MyStruct {
+                    //    f: 1usize,
+                    //    ..other_struct
+                    // };
+                    // ```
+                    // will have the `other_struct` expression constrained to
+                    // `MyStruct<'a, _, F2, C>`, as opposed to just `_`...
+                    // This is important to allow coercions to happen in
+                    // `other_struct` itself. See `coerce-in-base-expr.rs`.
+                    let fresh_base_ty = self.tcx.mk_adt(*adt, fresh_substs);
+                    self.check_expr_has_type_or_error(
+                        base_expr,
+                        self.resolve_vars_if_possible(fresh_base_ty),
+                        |_| {},
+                    );
+                    fru_tys
+                } else {
+                    // Check the base_expr, regardless of a bad expected adt_ty, so we can get
+                    // type errors on that expression, too.
+                    self.check_expr(base_expr);
+                    self.tcx
+                        .sess
+                        .emit_err(FunctionalRecordUpdateOnNonStruct { span: base_expr.span });
+                    return;
                 }
             } else {
                 self.check_expr_has_type_or_error(base_expr, adt_ty, |_| {
@@ -1597,13 +1700,18 @@
                 }
             };
             self.typeck_results.borrow_mut().fru_field_types_mut().insert(expr_id, fru_tys);
-        } else if kind_name != "union" && !remaining_fields.is_empty() {
-            let inaccessible_remaining_fields = remaining_fields.iter().any(|(_, (_, field))| {
-                !field.vis.is_accessible_from(tcx.parent_module(expr_id).to_def_id(), tcx)
-            });
+        } else if adt_kind != AdtKind::Union && !remaining_fields.is_empty() {
+            debug!(?remaining_fields);
+            let private_fields: Vec<&ty::FieldDef> = variant
+                .fields
+                .iter()
+                .filter(|field| {
+                    !field.vis.is_accessible_from(tcx.parent_module(expr_id).to_def_id(), tcx)
+                })
+                .collect();
 
-            if inaccessible_remaining_fields {
-                self.report_inaccessible_fields(adt_ty, span);
+            if !private_fields.is_empty() {
+                self.report_private_fields(adt_ty, span, private_fields, ast_fields);
             } else {
                 self.report_missing_fields(
                     adt_ty,
@@ -1716,7 +1824,7 @@
             err.span_suggestion(
                 range_start.span.shrink_to_hi(),
                 &format!("to set the remaining fields{instead}, separate the last named field with a comma"),
-                ",".to_string(),
+                ",",
                 Applicability::MaybeIncorrect,
             );
         }
@@ -1727,7 +1835,7 @@
     /// Report an error for a struct field expression when there are invisible fields.
     ///
     /// ```text
-    /// error: cannot construct `Foo` with struct literal syntax due to inaccessible fields
+    /// error: cannot construct `Foo` with struct literal syntax due to private fields
     ///  --> src/main.rs:8:5
     ///   |
     /// 8 |     foo::Foo {};
@@ -1735,13 +1843,54 @@
     ///
     /// error: aborting due to previous error
     /// ```
-    fn report_inaccessible_fields(&self, adt_ty: Ty<'tcx>, span: Span) {
-        self.tcx.sess.span_err(
+    fn report_private_fields(
+        &self,
+        adt_ty: Ty<'tcx>,
+        span: Span,
+        private_fields: Vec<&ty::FieldDef>,
+        used_fields: &'tcx [hir::ExprField<'tcx>],
+    ) {
+        let mut err = self.tcx.sess.struct_span_err(
             span,
             &format!(
-                "cannot construct `{adt_ty}` with struct literal syntax due to inaccessible fields",
+                "cannot construct `{adt_ty}` with struct literal syntax due to private fields",
             ),
         );
+        let (used_private_fields, remaining_private_fields): (
+            Vec<(Symbol, Span, bool)>,
+            Vec<(Symbol, Span, bool)>,
+        ) = private_fields
+            .iter()
+            .map(|field| {
+                match used_fields.iter().find(|used_field| field.name == used_field.ident.name) {
+                    Some(used_field) => (field.name, used_field.span, true),
+                    None => (field.name, self.tcx.def_span(field.did), false),
+                }
+            })
+            .partition(|field| field.2);
+        err.span_labels(used_private_fields.iter().map(|(_, span, _)| *span), "private field");
+        if !remaining_private_fields.is_empty() {
+            let remaining_private_fields_len = remaining_private_fields.len();
+            let names = match &remaining_private_fields
+                .iter()
+                .map(|(name, _, _)| name.to_string())
+                .collect::<Vec<_>>()[..]
+            {
+                _ if remaining_private_fields_len > 6 => String::new(),
+                [name] => format!("`{name}` "),
+                [names @ .., last] => {
+                    let names = names.iter().map(|name| format!("`{name}`")).collect::<Vec<_>>();
+                    format!("{} and `{last}` ", names.join(", "))
+                }
+                [] => unreachable!(),
+            };
+            err.note(format!(
+                "... and other private field{s} {names}that {were} not provided",
+                s = pluralize!(remaining_private_fields_len),
+                were = pluralize!("was", remaining_private_fields_len),
+            ));
+        }
+        err.emit();
     }
 
     fn report_unknown_field(
@@ -1838,7 +1987,7 @@
                     err.span_suggestion(
                         field.ident.span,
                         "a field with a similar name exists",
-                        field_name.to_string(),
+                        field_name,
                         Applicability::MaybeIncorrect,
                     );
                 } else {
@@ -2084,7 +2233,7 @@
                     err.span_suggestion_verbose(
                         base.span.shrink_to_hi(),
                         "consider `await`ing on the `Future` and access the field of its `Output`",
-                        ".await".to_string(),
+                        ".await",
                         Applicability::MaybeIncorrect,
                     );
                 }
@@ -2284,7 +2433,7 @@
             err.span_suggestion(
                 field.span,
                 "a field with a similar name exists",
-                suggested_field_name.to_string(),
+                suggested_field_name,
                 Applicability::MaybeIncorrect,
             );
         } else {
@@ -2387,11 +2536,11 @@
         err
     }
 
-    crate fn get_field_candidates(
+    pub(crate) fn get_field_candidates(
         &self,
         span: Span,
         base_t: Ty<'tcx>,
-    ) -> Option<(&Vec<ty::FieldDef>, SubstsRef<'tcx>)> {
+    ) -> Option<(&[ty::FieldDef], SubstsRef<'tcx>)> {
         debug!("get_field_candidates(span: {:?}, base_t: {:?}", span, base_t);
 
         for (base_t, _) in self.autoderef(span, base_t) {
@@ -2412,7 +2561,7 @@
 
     /// This method is called after we have encountered a missing field error to recursively
     /// search for the field
-    crate fn check_for_nested_field_satisfying(
+    pub(crate) fn check_for_nested_field_satisfying(
         &self,
         span: Span,
         matches: &impl Fn(&ty::FieldDef, Ty<'tcx>) -> bool,
@@ -2598,10 +2747,10 @@
                         self.check_expr_asm_operand(out_expr, false);
                     }
                 }
-                hir::InlineAsmOperand::Const { anon_const }
-                | hir::InlineAsmOperand::SymFn { anon_const } => {
-                    self.to_const(anon_const);
-                }
+                // `AnonConst`s have their own body and is type-checked separately.
+                // As they don't flow into the type system we don't need them to
+                // be well-formed.
+                hir::InlineAsmOperand::Const { .. } | hir::InlineAsmOperand::SymFn { .. } => {}
                 hir::InlineAsmOperand::SymStatic { .. } => {}
             }
         }
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
index 4f8cfe0..ea7ebdf 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
@@ -4,6 +4,7 @@
 };
 use crate::check::callee::{self, DeferredCallResolution};
 use crate::check::method::{self, MethodCallee, SelfSource};
+use crate::check::rvalue_scopes;
 use crate::check::{BreakableCtxt, Diverges, Expectation, FnCtxt, LocalTy};
 
 use rustc_data_structures::captures::Captures;
@@ -620,6 +621,13 @@
         self.normalize_associated_types_in(span, field.ty(self.tcx, substs))
     }
 
+    pub(in super::super) fn resolve_rvalue_scopes(&self, def_id: DefId) {
+        let scope_tree = self.tcx.region_scope_tree(def_id);
+        let rvalue_scopes = { rvalue_scopes::resolve_rvalue_scopes(self, &scope_tree, def_id) };
+        let mut typeck_results = self.inh.typeck_results.borrow_mut();
+        typeck_results.rvalue_scopes = rvalue_scopes;
+    }
+
     pub(in super::super) fn resolve_generator_interiors(&self, def_id: DefId) {
         let mut generators = self.deferred_generator_interiors.borrow_mut();
         for (body_id, interior, kind) in generators.drain(..) {
@@ -755,9 +763,9 @@
         expected_ret: Expectation<'tcx>,
         formal_ret: Ty<'tcx>,
         formal_args: &[Ty<'tcx>],
-    ) -> Vec<Ty<'tcx>> {
+    ) -> Option<Vec<Ty<'tcx>>> {
         let formal_ret = self.resolve_vars_with_obligations(formal_ret);
-        let Some(ret_ty) = expected_ret.only_has_type(self) else { return vec![]; };
+        let ret_ty = expected_ret.only_has_type(self)?;
 
         // HACK(oli-obk): This is a hack to keep RPIT and TAIT in sync wrt their behaviour.
         // Without it, the inference
@@ -779,7 +787,7 @@
                 if let ty::subst::GenericArgKind::Type(ty) = ty.unpack() {
                     if let ty::Opaque(def_id, _) = *ty.kind() {
                         if self.infcx.opaque_type_origin(def_id, DUMMY_SP).is_some() {
-                            return vec![];
+                            return None;
                         }
                     }
                 }
@@ -820,7 +828,7 @@
 
                 // Record all the argument types, with the substitutions
                 // produced from the above subtyping unification.
-                Ok(formal_args.iter().map(|&ty| self.resolve_vars_if_possible(ty)).collect())
+                Ok(Some(formal_args.iter().map(|&ty| self.resolve_vars_if_possible(ty)).collect()))
             })
             .unwrap_or_default();
         debug!(?formal_args, ?formal_ret, ?expect_args, ?expected_ret);
@@ -1220,6 +1228,7 @@
                     None
                 }
             }),
+            |_| {},
         );
 
         if let Res::Local(hid) = res {
@@ -1301,7 +1310,7 @@
                                 err.span_suggestion(
                                     span,
                                     "use curly brackets",
-                                    String::from("Self { /* fields */ }"),
+                                    "Self { /* fields */ }",
                                     Applicability::HasPlaceholders,
                                 );
                             }
@@ -1486,7 +1495,12 @@
     }
 
     /// Add all the obligations that are required, substituting and normalized appropriately.
-    crate fn add_required_obligations(&self, span: Span, def_id: DefId, substs: &SubstsRef<'tcx>) {
+    pub(crate) fn add_required_obligations(
+        &self,
+        span: Span,
+        def_id: DefId,
+        substs: &SubstsRef<'tcx>,
+    ) {
         self.add_required_obligations_with_code(
             span,
             def_id,
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/arg_matrix.rs b/compiler/rustc_typeck/src/check/fn_ctxt/arg_matrix.rs
new file mode 100644
index 0000000..b7ba9d9
--- /dev/null
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/arg_matrix.rs
@@ -0,0 +1,351 @@
+use std::cmp;
+
+use rustc_middle::ty::error::TypeError;
+
+// An issue that might be found in the compatibility matrix
+#[derive(Debug)]
+enum Issue {
+    /// The given argument is the invalid type for the input
+    Invalid(usize),
+    /// There is a missing input
+    Missing(usize),
+    /// There's a superfluous argument
+    Extra(usize),
+    /// Two arguments should be swapped
+    Swap(usize, usize),
+    /// Several arguments should be reordered
+    Permutation(Vec<Option<usize>>),
+}
+
+#[derive(Clone, Debug)]
+pub(crate) enum Compatibility<'tcx> {
+    Compatible,
+    Incompatible(Option<TypeError<'tcx>>),
+}
+
+/// Similar to `Issue`, but contains some extra information
+#[derive(Debug)]
+pub(crate) enum Error<'tcx> {
+    /// The provided argument is the invalid type for the expected input
+    Invalid(usize, usize, Compatibility<'tcx>), // provided, expected
+    /// There is a missing input
+    Missing(usize),
+    /// There's a superfluous argument
+    Extra(usize),
+    /// Two arguments should be swapped
+    Swap(usize, usize, usize, usize),
+    /// Several arguments should be reordered
+    Permutation(Vec<(usize, usize)>), // dest_arg, dest_input
+}
+
+pub(crate) struct ArgMatrix<'tcx> {
+    /// Maps the indices in the `compatibility_matrix` rows to the indices of
+    /// the *user provided* inputs
+    input_indexes: Vec<usize>,
+    /// Maps the indices in the `compatibility_matrix` columns to the indices
+    /// of the *expected* args
+    arg_indexes: Vec<usize>,
+    /// The first dimension (rows) are the remaining user provided inputs to
+    /// match and the second dimension (cols) are the remaining expected args
+    /// to match
+    compatibility_matrix: Vec<Vec<Compatibility<'tcx>>>,
+}
+
+impl<'tcx> ArgMatrix<'tcx> {
+    pub(crate) fn new<F: FnMut(usize, usize) -> Compatibility<'tcx>>(
+        minimum_input_count: usize,
+        provided_arg_count: usize,
+        mut is_compatible: F,
+    ) -> Self {
+        let compatibility_matrix = (0..provided_arg_count)
+            .map(|i| (0..minimum_input_count).map(|j| is_compatible(i, j)).collect())
+            .collect();
+        ArgMatrix {
+            input_indexes: (0..provided_arg_count).collect(),
+            arg_indexes: (0..minimum_input_count).collect(),
+            compatibility_matrix,
+        }
+    }
+
+    /// Remove a given input from consideration
+    fn eliminate_input(&mut self, idx: usize) {
+        self.input_indexes.remove(idx);
+        self.compatibility_matrix.remove(idx);
+    }
+
+    /// Remove a given argument from consideration
+    fn eliminate_arg(&mut self, idx: usize) {
+        self.arg_indexes.remove(idx);
+        for row in &mut self.compatibility_matrix {
+            row.remove(idx);
+        }
+    }
+
+    /// "satisfy" an input with a given arg, removing both from consideration
+    fn satisfy_input(&mut self, input_idx: usize, arg_idx: usize) {
+        self.eliminate_input(input_idx);
+        self.eliminate_arg(arg_idx);
+    }
+
+    // Returns a `Vec` of (user input, expected arg) of matched arguments. These
+    // are inputs on the remaining diagonal that match.
+    fn eliminate_satisfied(&mut self) -> Vec<(usize, usize)> {
+        let mut i = cmp::min(self.input_indexes.len(), self.arg_indexes.len());
+        let mut eliminated = vec![];
+        while i > 0 {
+            let idx = i - 1;
+            if matches!(self.compatibility_matrix[idx][idx], Compatibility::Compatible) {
+                eliminated.push((self.input_indexes[idx], self.arg_indexes[idx]));
+                self.satisfy_input(idx, idx);
+            }
+            i -= 1;
+        }
+        return eliminated;
+    }
+
+    // Find some issue in the compatibility matrix
+    fn find_issue(&self) -> Option<Issue> {
+        let mat = &self.compatibility_matrix;
+        let ai = &self.arg_indexes;
+        let ii = &self.input_indexes;
+
+        for i in 0..cmp::max(ai.len(), ii.len()) {
+            // If we eliminate the last row, any left-over inputs are considered missing
+            if i >= mat.len() {
+                return Some(Issue::Missing(i));
+            }
+            // If we eliminate the last column, any left-over arguments are extra
+            if mat[i].len() == 0 {
+                return Some(Issue::Extra(i));
+            }
+
+            // Make sure we don't pass the bounds of our matrix
+            let is_arg = i < ai.len();
+            let is_input = i < ii.len();
+            if is_arg && is_input && matches!(mat[i][i], Compatibility::Compatible) {
+                // This is a satisfied input, so move along
+                continue;
+            }
+
+            let mut useless = true;
+            let mut unsatisfiable = true;
+            if is_arg {
+                for j in 0..ii.len() {
+                    // If we find at least one input this argument could satisfy
+                    // this argument isn't unsatisfiable
+                    if matches!(mat[j][i], Compatibility::Compatible) {
+                        unsatisfiable = false;
+                        break;
+                    }
+                }
+            }
+            if is_input {
+                for j in 0..ai.len() {
+                    // If we find at least one argument that could satisfy this input
+                    // this argument isn't useless
+                    if matches!(mat[i][j], Compatibility::Compatible) {
+                        useless = false;
+                        break;
+                    }
+                }
+            }
+
+            match (is_input, is_arg, useless, unsatisfiable) {
+                // If an argument is unsatisfied, and the input in its position is useless
+                // then the most likely explanation is that we just got the types wrong
+                (true, true, true, true) => return Some(Issue::Invalid(i)),
+                // Otherwise, if an input is useless, then indicate that this is an extra argument
+                (true, _, true, _) => return Some(Issue::Extra(i)),
+                // Otherwise, if an argument is unsatisfiable, indicate that it's missing
+                (_, true, _, true) => return Some(Issue::Missing(i)),
+                (true, true, _, _) => {
+                    // The argument isn't useless, and the input isn't unsatisfied,
+                    // so look for a parameter we might swap it with
+                    // We look for swaps explicitly, instead of just falling back on permutations
+                    // so that cases like (A,B,C,D) given (B,A,D,C) show up as two swaps,
+                    // instead of a large permutation of 4 elements.
+                    for j in 0..cmp::min(ai.len(), ii.len()) {
+                        if i == j || matches!(mat[j][j], Compatibility::Compatible) {
+                            continue;
+                        }
+                        if matches!(mat[i][j], Compatibility::Compatible)
+                            && matches!(mat[j][i], Compatibility::Compatible)
+                        {
+                            return Some(Issue::Swap(i, j));
+                        }
+                    }
+                }
+                _ => {
+                    continue;
+                }
+            }
+        }
+
+        // We didn't find any of the individual issues above, but
+        // there might be a larger permutation of parameters, so we now check for that
+        // by checking for cycles
+        // We use a double option at position i in this vec to represent:
+        // - None: We haven't computed anything about this argument yet
+        // - Some(None): This argument definitely doesn't participate in a cycle
+        // - Some(Some(x)): the i-th argument could permute to the x-th position
+        let mut permutation: Vec<Option<Option<usize>>> = vec![None; mat.len()];
+        let mut permutation_found = false;
+        for i in 0..mat.len() {
+            if permutation[i].is_some() {
+                // We've already decided whether this argument is or is not in a loop
+                continue;
+            }
+
+            let mut stack = vec![];
+            let mut j = i;
+            let mut last = i;
+            let mut is_cycle = true;
+            loop {
+                stack.push(j);
+                // Look for params this one could slot into
+                let compat: Vec<_> =
+                    mat[j]
+                        .iter()
+                        .enumerate()
+                        .filter_map(|(i, c)| {
+                            if matches!(c, Compatibility::Compatible) { Some(i) } else { None }
+                        })
+                        .collect();
+                if compat.len() != 1 {
+                    // this could go into multiple slots, don't bother exploring both
+                    is_cycle = false;
+                    break;
+                }
+                j = compat[0];
+                if stack.contains(&j) {
+                    last = j;
+                    break;
+                }
+            }
+            if stack.len() <= 2 {
+                // If we encounter a cycle of 1 or 2 elements, we'll let the
+                // "satisfy" and "swap" code above handle those
+                is_cycle = false;
+            }
+            // We've built up some chain, some of which might be a cycle
+            // ex: [1,2,3,4]; last = 2; j = 2;
+            // So, we want to mark 4, 3, and 2 as part of a permutation
+            permutation_found = is_cycle;
+            while let Some(x) = stack.pop() {
+                if is_cycle {
+                    permutation[x] = Some(Some(j));
+                    j = x;
+                    if j == last {
+                        // From here on out, we're a tail leading into a cycle,
+                        // not the cycle itself
+                        is_cycle = false;
+                    }
+                } else {
+                    // Some(None) ensures we save time by skipping this argument again
+                    permutation[x] = Some(None);
+                }
+            }
+        }
+
+        if permutation_found {
+            // Map unwrap to remove the first layer of Some
+            let final_permutation: Vec<Option<usize>> =
+                permutation.into_iter().map(|x| x.unwrap()).collect();
+            return Some(Issue::Permutation(final_permutation));
+        }
+        return None;
+    }
+
+    // Obviously, detecting exact user intention is impossible, so the goal here is to
+    // come up with as likely of a story as we can to be helpful.
+    //
+    // We'll iteratively removed "satisfied" input/argument pairs,
+    // then check for the cases above, until we've eliminated the entire grid
+    //
+    // We'll want to know which arguments and inputs these rows and columns correspond to
+    // even after we delete them.
+    pub(crate) fn find_errors(mut self) -> (Vec<Error<'tcx>>, Vec<Option<usize>>) {
+        let provided_arg_count = self.input_indexes.len();
+
+        let mut errors: Vec<Error<'tcx>> = vec![];
+        // For each expected argument, the matched *actual* input
+        let mut matched_inputs: Vec<Option<usize>> = vec![None; self.arg_indexes.len()];
+
+        // Before we start looking for issues, eliminate any arguments that are already satisfied,
+        // so that an argument which is already spoken for by the input it's in doesn't
+        // spill over into another similarly typed input
+        // ex:
+        //   fn some_func(_a: i32, _b: i32) {}
+        //   some_func(1, "");
+        // Without this elimination, the first argument causes the second argument
+        // to show up as both a missing input and extra argument, rather than
+        // just an invalid type.
+        for (inp, arg) in self.eliminate_satisfied() {
+            matched_inputs[arg] = Some(inp);
+        }
+
+        while self.input_indexes.len() > 0 || self.arg_indexes.len() > 0 {
+            match self.find_issue() {
+                Some(Issue::Invalid(idx)) => {
+                    let compatibility = self.compatibility_matrix[idx][idx].clone();
+                    let input_idx = self.input_indexes[idx];
+                    let arg_idx = self.arg_indexes[idx];
+                    self.satisfy_input(idx, idx);
+                    errors.push(Error::Invalid(input_idx, arg_idx, compatibility));
+                }
+                Some(Issue::Extra(idx)) => {
+                    let input_idx = self.input_indexes[idx];
+                    self.eliminate_input(idx);
+                    errors.push(Error::Extra(input_idx));
+                }
+                Some(Issue::Missing(idx)) => {
+                    let arg_idx = self.arg_indexes[idx];
+                    self.eliminate_arg(idx);
+                    errors.push(Error::Missing(arg_idx));
+                }
+                Some(Issue::Swap(idx, other)) => {
+                    let input_idx = self.input_indexes[idx];
+                    let other_input_idx = self.input_indexes[other];
+                    let arg_idx = self.arg_indexes[idx];
+                    let other_arg_idx = self.arg_indexes[other];
+                    let (min, max) = (cmp::min(idx, other), cmp::max(idx, other));
+                    self.satisfy_input(min, max);
+                    // Subtract 1 because we already removed the "min" row
+                    self.satisfy_input(max - 1, min);
+                    errors.push(Error::Swap(input_idx, other_input_idx, arg_idx, other_arg_idx));
+                    matched_inputs[other_arg_idx] = Some(input_idx);
+                    matched_inputs[arg_idx] = Some(other_input_idx);
+                }
+                Some(Issue::Permutation(args)) => {
+                    let mut idxs: Vec<usize> = args.iter().filter_map(|&a| a).collect();
+
+                    let mut real_idxs = vec![None; provided_arg_count];
+                    for (src, dst) in
+                        args.iter().enumerate().filter_map(|(src, dst)| dst.map(|dst| (src, dst)))
+                    {
+                        let src_input_idx = self.input_indexes[src];
+                        let dst_input_idx = self.input_indexes[dst];
+                        let dest_arg_idx = self.arg_indexes[dst];
+                        real_idxs[src_input_idx] = Some((dest_arg_idx, dst_input_idx));
+                        matched_inputs[dest_arg_idx] = Some(src_input_idx);
+                    }
+                    idxs.sort();
+                    idxs.reverse();
+                    for i in idxs {
+                        self.satisfy_input(i, i);
+                    }
+                    errors.push(Error::Permutation(real_idxs.into_iter().flatten().collect()));
+                }
+                None => {
+                    // We didn't find any issues, so we need to push the algorithm forward
+                    // First, eliminate any arguments that currently satisfy their inputs
+                    for (inp, arg) in self.eliminate_satisfied() {
+                        matched_inputs[arg] = Some(inp);
+                    }
+                }
+            };
+        }
+
+        return (errors, matched_inputs);
+    }
+}
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
index 09179b1..6633bd5 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
@@ -1,5 +1,6 @@
 use crate::astconv::AstConv;
 use crate::check::coercion::CoerceMany;
+use crate::check::fn_ctxt::arg_matrix::{ArgMatrix, Compatibility, Error};
 use crate::check::gather_locals::Declaration;
 use crate::check::method::MethodCallee;
 use crate::check::Expectation::*;
@@ -11,15 +12,18 @@
 use crate::structured_errors::StructuredDiagnostic;
 
 use rustc_ast as ast;
-use rustc_data_structures::sync::Lrc;
 use rustc_errors::{Applicability, Diagnostic, DiagnosticId, MultiSpan};
 use rustc_hir as hir;
 use rustc_hir::def::{CtorOf, DefKind, Res};
 use rustc_hir::def_id::DefId;
 use rustc_hir::{ExprKind, Node, QPath};
+use rustc_infer::infer::error_reporting::{FailureCode, ObligationCauseExt};
+use rustc_infer::infer::InferOk;
+use rustc_infer::infer::TypeTrace;
 use rustc_middle::ty::adjustment::AllowTwoPhase;
+use rustc_middle::ty::error::TypeError;
 use rustc_middle::ty::fold::TypeFoldable;
-use rustc_middle::ty::{self, Ty};
+use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_session::Session;
 use rustc_span::symbol::Ident;
 use rustc_span::{self, Span};
@@ -43,6 +47,23 @@
         }
     }
 
+    pub(in super::super) fn check_transmutes(&self) {
+        let mut deferred_transmute_checks = self.deferred_transmute_checks.borrow_mut();
+        debug!("FnCtxt::check_transmutes: {} deferred checks", deferred_transmute_checks.len());
+        for (from, to, span) in deferred_transmute_checks.drain(..) {
+            self.check_transmute(span, from, to);
+        }
+    }
+
+    pub(in super::super) fn check_asms(&self) {
+        let mut deferred_asm_checks = self.deferred_asm_checks.borrow_mut();
+        debug!("FnCtxt::check_asm: {} deferred checks", deferred_asm_checks.len());
+        for (asm, hir_id) in deferred_asm_checks.drain(..) {
+            let enclosing_id = self.tcx.hir().enclosing_body_owner(hir_id);
+            self.check_asm(asm, enclosing_id);
+        }
+    }
+
     pub(in super::super) fn check_method_argument_types(
         &self,
         sp: Span,
@@ -68,7 +89,7 @@
                 sp,
                 expr,
                 &err_inputs,
-                vec![],
+                None,
                 args_no_rcvr,
                 false,
                 tuple_arguments,
@@ -109,7 +130,7 @@
         // Types (as defined in the *signature* of the target function)
         formal_input_tys: &[Ty<'tcx>],
         // More specific expected types, after unifying with caller output types
-        expected_input_tys: Vec<Ty<'tcx>>,
+        expected_input_tys: Option<Vec<Ty<'tcx>>>,
         // The expressions for each provided argument
         provided_args: &'tcx [hir::Expr<'tcx>],
         // Whether the function is variadic, for example when imported from C
@@ -120,10 +141,18 @@
         fn_def_id: Option<DefId>,
     ) {
         let tcx = self.tcx;
-        // Grab the argument types, supplying fresh type variables
-        // if the wrong number of arguments were supplied
-        let supplied_arg_count =
-            if tuple_arguments == DontTupleArguments { provided_args.len() } else { 1 };
+
+        // Conceptually, we've got some number of expected inputs, and some number of provided aguments
+        // and we can form a grid of whether each argument could satisfy a given input:
+        //      in1 | in2 | in3 | ...
+        // arg1  ?  |     |     |
+        // arg2     |  ?  |     |
+        // arg3     |     |  ?  |
+        // ...
+        // Initially, we just check the diagonal, because in the case of correct code
+        // these are the only checks that matter
+        // However, in the unhappy path, we'll fill in this whole grid to attempt to provide
+        // better error messages about invalid method calls.
 
         // All the input types from the fn signature must outlive the call
         // so as to validate implied bounds.
@@ -131,10 +160,7 @@
             self.register_wf_obligation(fn_input_ty.into(), arg_expr.span, traits::MiscObligation);
         }
 
-        let expected_arg_count = formal_input_tys.len();
-
-        // expected_count, arg_count, error_code, sugg_tuple_wrap_args
-        let mut arg_count_error: Option<(usize, usize, &str, TupleMatchFound)> = None;
+        let mut err_code = "E0061";
 
         // If the arguments should be wrapped in a tuple (ex: closures), unwrap them here
         let (formal_input_tys, expected_input_tys) = if tuple_arguments == TupleArguments {
@@ -144,19 +170,17 @@
                 ty::Tuple(arg_types) => {
                     // Argument length differs
                     if arg_types.len() != provided_args.len() {
-                        arg_count_error = Some((
-                            arg_types.len(),
-                            provided_args.len(),
-                            "E0057",
-                            TupleMatchFound::None,
-                        ));
+                        err_code = "E0057";
                     }
-                    let expected_input_tys = match expected_input_tys.get(0) {
-                        Some(&ty) => match ty.kind() {
-                            ty::Tuple(tys) => tys.iter().collect(),
-                            _ => vec![],
+                    let expected_input_tys = match expected_input_tys {
+                        Some(expected_input_tys) => match expected_input_tys.get(0) {
+                            Some(ty) => match ty.kind() {
+                                ty::Tuple(tys) => Some(tys.iter().collect()),
+                                _ => None,
+                            },
+                            None => None,
                         },
-                        None => vec![],
+                        None => None,
                     };
                     (arg_types.iter().collect(), expected_input_tys)
                 }
@@ -171,53 +195,25 @@
                          for the function trait is neither a tuple nor unit"
                     )
                     .emit();
-                    (self.err_args(provided_args.len()), vec![])
+                    (self.err_args(provided_args.len()), None)
                 }
             }
-        } else if expected_arg_count == supplied_arg_count {
-            (formal_input_tys.to_vec(), expected_input_tys)
-        } else if c_variadic {
-            if supplied_arg_count >= expected_arg_count {
-                (formal_input_tys.to_vec(), expected_input_tys)
-            } else {
-                arg_count_error =
-                    Some((expected_arg_count, supplied_arg_count, "E0060", TupleMatchFound::None));
-                (self.err_args(supplied_arg_count), vec![])
-            }
         } else {
-            // are we passing elements of a tuple without the tuple parentheses?
-            let expected_input_tys = if expected_input_tys.is_empty() {
-                // In most cases we can use expected_input_tys, but some callers won't have the type
-                // information, in which case we fall back to the types from the input expressions.
-                formal_input_tys
-            } else {
-                &*expected_input_tys
-            };
-
-            let sugg_tuple_wrap_args = self.suggested_tuple_wrap(expected_input_tys, provided_args);
-
-            arg_count_error =
-                Some((expected_arg_count, supplied_arg_count, "E0061", sugg_tuple_wrap_args));
-            (self.err_args(supplied_arg_count), vec![])
+            (formal_input_tys.to_vec(), expected_input_tys)
         };
 
-        debug!(
-            "check_argument_types: formal_input_tys={:?}",
-            formal_input_tys.iter().map(|t| self.ty_to_string(*t)).collect::<Vec<String>>()
-        );
-
-        // If there is no expectation, expect formal_input_tys.
-        let expected_input_tys = if !expected_input_tys.is_empty() {
+        // If there are no external expectations at the call site, just use the types from the function defn
+        let expected_input_tys = if let Some(expected_input_tys) = expected_input_tys {
+            assert_eq!(expected_input_tys.len(), formal_input_tys.len());
             expected_input_tys
         } else {
             formal_input_tys.clone()
         };
 
-        assert_eq!(expected_input_tys.len(), formal_input_tys.len());
+        let minimum_input_count = expected_input_tys.len();
+        let provided_arg_count = provided_args.len();
 
-        let provided_arg_count: usize = provided_args.len();
-
-        // Keep track of the fully coerced argument types
+        // We'll also want to keep track of the fully coerced argument types, for an awkward hack near the end
         let mut final_arg_types: Vec<Option<(Ty<'_>, Ty<'_>)>> = vec![None; provided_arg_count];
 
         // We introduce a helper function to demand that a given argument satisfy a given input
@@ -230,8 +226,9 @@
 
             debug!("checking argument {}: {:?} = {:?}", idx, provided_arg, formal_input_ty);
 
-            // The special-cased logic below has three functions:
-            // 1. Provide as good of an expected type as possible.
+            // We're on the happy path here, so we'll do a more involved check and write back types
+            // To check compatibility, we'll do 3 things:
+            // 1. Unify the provided argument with the expected type
             let expectation = Expectation::rvalue_hint(self, expected_input_ty);
 
             let checked_ty = self.check_expr_with_expectation(provided_arg, expectation);
@@ -245,8 +242,7 @@
             final_arg_types[idx] = Some((checked_ty, coerced_ty));
 
             // Cause selection errors caused by resolving a single argument to point at the
-            // argument and not the call. This is otherwise redundant with the `demand_coerce`
-            // call immediately after, but it lets us customize the span pointed to in the
+            // argument and not the call. This lets us customize the span pointed to in the
             // fulfillment error to be more accurate.
             let coerced_ty =
                 self.resolve_vars_with_obligations_and_mutate_fulfillment(coerced_ty, |errors| {
@@ -260,18 +256,91 @@
                     );
                 });
 
+            // Make sure we store the resolved type
             final_arg_types[idx] = Some((checked_ty, coerced_ty));
 
-            // We're processing function arguments so we definitely want to use
-            // two-phase borrows.
-            self.demand_coerce(&provided_arg, checked_ty, coerced_ty, None, AllowTwoPhase::Yes);
+            let coerce_error = self
+                .try_coerce(provided_arg, checked_ty, coerced_ty, AllowTwoPhase::Yes, None)
+                .err();
 
-            // 3. Relate the expected type and the formal one,
-            //    if the expected type was used for the coercion.
-            self.demand_suptype(provided_arg.span, formal_input_ty, coerced_ty);
+            if coerce_error.is_some() {
+                return Compatibility::Incompatible(coerce_error);
+            }
+
+            // 3. Check if the formal type is a supertype of the checked one
+            //    and register any such obligations for future type checks
+            let supertype_error = self
+                .at(&self.misc(provided_arg.span), self.param_env)
+                .sup(formal_input_ty, coerced_ty);
+            let subtyping_error = match supertype_error {
+                Ok(InferOk { obligations, value: () }) => {
+                    self.register_predicates(obligations);
+                    None
+                }
+                Err(err) => Some(err),
+            };
+
+            // If neither check failed, the types are compatible
+            match subtyping_error {
+                None => Compatibility::Compatible,
+                Some(_) => Compatibility::Incompatible(subtyping_error),
+            }
         };
 
-        let minimum_input_count = formal_input_tys.len();
+        // A "softer" version of the helper above, which checks types without persisting them,
+        // and treats error types differently
+        // This will allow us to "probe" for other argument orders that would likely have been correct
+        let check_compatible = |input_idx, arg_idx| {
+            let formal_input_ty: Ty<'tcx> = formal_input_tys[arg_idx];
+            let expected_input_ty: Ty<'tcx> = expected_input_tys[arg_idx];
+
+            // If either is an error type, we defy the usual convention and consider them to *not* be
+            // coercible.  This prevents our error message heuristic from trying to pass errors into
+            // every argument.
+            if formal_input_ty.references_error() || expected_input_ty.references_error() {
+                return Compatibility::Incompatible(None);
+            }
+
+            let provided_arg: &hir::Expr<'tcx> = &provided_args[input_idx];
+            let expectation = Expectation::rvalue_hint(self, expected_input_ty);
+            let already_checked_ty = self.typeck_results.borrow().expr_ty_adjusted_opt(provided_arg);
+            let checked_ty = already_checked_ty.unwrap_or_else(|| self.check_expr(provided_arg));
+
+            let coerced_ty = expectation.only_has_type(self).unwrap_or(formal_input_ty);
+            let can_coerce = self.can_coerce(checked_ty, coerced_ty);
+
+            if !can_coerce {
+                return Compatibility::Incompatible(None);
+            }
+
+            let subtyping_result = self
+                .at(&self.misc(provided_arg.span), self.param_env)
+                .sup(formal_input_ty, coerced_ty);
+
+            // Same as above: if either the coerce type or the checked type is an error type,
+            // consider them *not* compatible.
+            let coercible =
+                !coerced_ty.references_error() && !checked_ty.references_error() && can_coerce;
+
+            match (coercible, &subtyping_result) {
+                (true, Ok(_)) => Compatibility::Compatible,
+                _ => Compatibility::Incompatible(subtyping_result.err()),
+            }
+        };
+
+        // To start, we only care "along the diagonal", where we expect every
+        // provided arg to be in the right spot
+        let mut compatibility = vec![Compatibility::Incompatible(None); provided_args.len()];
+
+        // Keep track of whether we *could possibly* be satisfied, i.e. whether we're on the happy path
+        // if the wrong number of arguments were supplied, we CAN'T be satisfied,
+        // and if we're c_variadic, the supplied arguments must be >= the minimum count from the function
+        // otherwise, they need to be identical, because rust doesn't currently support variadic functions
+        let mut call_appears_satisfied = if c_variadic {
+            provided_arg_count >= minimum_input_count
+        } else {
+            provided_arg_count == minimum_input_count
+        };
 
         // Check the arguments.
         // We do this in a pretty awful way: first we type-check any arguments
@@ -295,6 +364,8 @@
                 })
             }
 
+            // Check each argument, to satisfy the input it was provided for
+            // Visually, we're traveling down the diagonal of the compatibility matrix
             for (idx, arg) in provided_args.iter().enumerate() {
                 // Warn only for the first loop (the "no closures" one).
                 // Closure arguments themselves can't be diverging, but
@@ -312,18 +383,87 @@
                     continue;
                 }
 
-                let is_closure = matches!(arg.kind, ExprKind::Closure(..));
+                let is_closure = matches!(arg.kind, ExprKind::Closure { .. });
                 if is_closure != check_closures {
                     continue;
                 }
 
-                demand_compatible(idx, &mut final_arg_types);
+                let compatible = demand_compatible(idx, &mut final_arg_types);
+                let is_compatible = matches!(compatible, Compatibility::Compatible);
+                compatibility[idx] = compatible;
+
+                if !is_compatible {
+                    call_appears_satisfied = false;
+                }
             }
         }
 
-        // If there was an error in parameter count, emit that here
-        if let Some((expected_count, arg_count, err_code, sugg_tuple_wrap_args)) = arg_count_error {
-            let (span, start_span, args, ctor_of) = match &call_expr.kind {
+        // Logic here is a bit hairy
+        'errors: {
+            // If something above didn't typecheck, we've fallen off the happy path
+            // and we should make some effort to provide better error messages
+            if call_appears_satisfied {
+                break 'errors;
+            }
+
+            self.set_tainted_by_errors();
+
+            // The algorithm here is inspired by levenshtein distance and longest common subsequence.
+            // We'll try to detect 4 different types of mistakes:
+            // - An extra parameter has been provided that doesn't satisfy *any* of the other inputs
+            // - An input is missing, which isn't satisfied by *any* of the other arguments
+            // - Some number of arguments have been provided in the wrong order
+            // - A type is straight up invalid
+
+            // First, let's find the errors
+            let mut compatibility: Vec<_> = compatibility.into_iter().map(Some).collect();
+            let (mut errors, matched_inputs) =
+                ArgMatrix::new(minimum_input_count, provided_arg_count, |i, j| {
+                    if i == j { compatibility[i].take().unwrap() } else { check_compatible(i, j) }
+                })
+                .find_errors();
+
+            // Okay, so here's where it gets complicated in regards to what errors
+            // we emit and how.
+            // There are 3 different "types" of errors we might encounter.
+            //   1) Missing/extra/swapped arguments
+            //   2) Valid but incorrect arguments
+            //   3) Invalid arguments
+            //      - Currently I think this only comes up with `CyclicTy`
+            //
+            // We first need to go through, remove those from (3) and emit those
+            // as their own error, particularly since they're error code and
+            // message is special. From what I can tell, we *must* emit these
+            // here (vs somewhere prior to this function) since the arguments
+            // become invalid *because* of how they get used in the function.
+            // It is what it is.
+
+            let found_errors = !errors.is_empty();
+
+            errors.drain_filter(|error| {
+                let Error::Invalid(input_idx, arg_idx, Compatibility::Incompatible(Some(e))) = error else { return false };
+                let expected_ty = expected_input_tys[*arg_idx];
+                let provided_ty = final_arg_types[*input_idx].map(|ty| ty.0).unwrap_or_else(|| tcx.ty_error());
+                let cause = &self.misc(provided_args[*input_idx].span);
+                let trace = TypeTrace::types(cause, true, expected_ty, provided_ty);
+                if !matches!(trace.cause.as_failure_code(e), FailureCode::Error0308(_)) {
+                    self.report_and_explain_type_error(trace, e).emit();
+                    return true;
+                }
+                false
+            });
+
+            // We're done if we found errors, but we already emitted them.
+            // I don't think we *should* be able to enter this bit of code
+            // (`!call_appears_satisfied`) without *also* finding errors, but we
+            // don't want to accidentally not emit an error if there is some
+            // logic bug in the `ArgMatrix` code.
+            if found_errors && errors.is_empty() {
+                break 'errors;
+            }
+
+            // Next, let's construct the error
+            let (error_span, full_call_span, ctor_of) = match &call_expr.kind {
                 hir::ExprKind::Call(
                     hir::Expr {
                         span,
@@ -334,129 +474,519 @@
                             )),
                         ..
                     },
-                    args,
-                ) => (*span, *span, &args[..], Some(of)),
-                hir::ExprKind::Call(hir::Expr { span, .. }, args) => {
-                    (*span, *span, &args[..], None)
+                    _,
+                ) => (call_span, *span, Some(of)),
+                hir::ExprKind::Call(hir::Expr { span, .. }, _) => (call_span, *span, None),
+                hir::ExprKind::MethodCall(path_segment, _, span) => {
+                    let ident_span = path_segment.ident.span;
+                    let ident_span = if let Some(args) = path_segment.args {
+                        ident_span.with_hi(args.span_ext.hi())
+                    } else {
+                        ident_span
+                    };
+                    (
+                        *span, ident_span, None, // methods are never ctors
+                    )
                 }
-                hir::ExprKind::MethodCall(path_segment, args, _) => (
-                    path_segment.ident.span,
-                    // `sp` doesn't point at the whole `foo.bar()`, only at `bar`.
-                    path_segment
-                        .args
-                        .and_then(|args| args.args.iter().last())
-                        // Account for `foo.bar::<T>()`.
-                        .map(|arg| {
-                            // Skip the closing `>`.
-                            tcx.sess
-                                .source_map()
-                                .next_point(tcx.sess.source_map().next_point(arg.span()))
-                        })
-                        .unwrap_or(path_segment.ident.span),
-                    &args[1..], // Skip the receiver.
-                    None,       // methods are never ctors
-                ),
                 k => span_bug!(call_span, "checking argument types on a non-call: `{:?}`", k),
             };
-            let arg_spans = if provided_args.is_empty() {
-                // foo()
-                // ^^^-- supplied 0 arguments
-                // |
-                // expected 2 arguments
-                vec![tcx.sess.source_map().next_point(start_span).with_hi(call_span.hi())]
-            } else {
-                // foo(1, 2, 3)
-                // ^^^ -  -  - supplied 3 arguments
-                // |
-                // expected 2 arguments
-                args.iter().map(|arg| arg.span).collect::<Vec<Span>>()
-            };
+            let args_span = error_span.trim_start(full_call_span).unwrap_or(error_span);
             let call_name = match ctor_of {
                 Some(CtorOf::Struct) => "struct",
                 Some(CtorOf::Variant) => "enum variant",
                 None => "function",
             };
-            let mut err = tcx.sess.struct_span_err_with_code(
-                span,
-                &format!(
-                    "this {} takes {}{} but {} {} supplied",
-                    call_name,
-                    if c_variadic { "at least " } else { "" },
-                    potentially_plural_count(expected_count, "argument"),
-                    potentially_plural_count(arg_count, "argument"),
-                    if arg_count == 1 { "was" } else { "were" }
-                ),
-                DiagnosticId::Error(err_code.to_owned()),
-            );
-            let label = format!("supplied {}", potentially_plural_count(arg_count, "argument"));
-            for (i, span) in arg_spans.into_iter().enumerate() {
-                err.span_label(
-                    span,
-                    if arg_count == 0 || i + 1 == arg_count { &label } else { "" },
-                );
+            if c_variadic && provided_arg_count < minimum_input_count {
+                err_code = "E0060";
             }
-            if let Some(def_id) = fn_def_id && let Some(def_span) = tcx.def_ident_span(def_id) {
-                let mut spans: MultiSpan = def_span.into();
 
-                let params = tcx
-                    .hir()
-                    .get_if_local(def_id)
-                    .and_then(|node| node.body_id())
-                    .into_iter()
-                    .map(|id| tcx.hir().body(id).params)
-                    .flatten();
-
-                for param in params {
-                    spans.push_span_label(param.span, String::new());
-                }
-
-                let def_kind = tcx.def_kind(def_id);
-                err.span_note(spans, &format!("{} defined here", def_kind.descr(def_id)));
-            }
+            // Next special case: The case where we expect a single tuple and
+            // wrapping all the args in parentheses (or adding a comma to
+            // already existing parentheses) will result in a tuple that
+            // satisfies the call.
+            // This isn't super ideal code, because we copy code from elsewhere
+            // and somewhat duplicate this. We also delegate to the general type
+            // mismatch suggestions for the single arg case.
+            let sugg_tuple_wrap_args =
+                self.suggested_tuple_wrap(&expected_input_tys, provided_args);
             match sugg_tuple_wrap_args {
+                TupleMatchFound::None => {}
                 TupleMatchFound::Single => {
-                    let sugg_span = tcx.sess.source_map().end_point(call_expr.span);
-                    // remove closing `)` from the span
-                    let sugg_span = sugg_span.shrink_to_lo();
-                    err.span_suggestion(
-                        sugg_span,
-                        "expected the unit value `()`; create it with empty parentheses",
-                        String::from("()"),
-                        Applicability::MachineApplicable,
+                    let expected_ty = expected_input_tys[0];
+                    let provided_ty = final_arg_types[0].map(|ty| ty.0).unwrap();
+                    let expected_ty = self.resolve_vars_if_possible(expected_ty);
+                    let provided_ty = self.resolve_vars_if_possible(provided_ty);
+                    let cause = &self.misc(provided_args[0].span);
+                    let compatibility = demand_compatible(0, &mut final_arg_types);
+                    let type_error = match compatibility {
+                        Compatibility::Incompatible(Some(error)) => error,
+                        _ => TypeError::Mismatch,
+                    };
+                    let trace = TypeTrace::types(cause, true, expected_ty, provided_ty);
+                    let mut err = self.report_and_explain_type_error(trace, &type_error);
+                    self.emit_coerce_suggestions(
+                        &mut err,
+                        &provided_args[0],
+                        final_arg_types[0].map(|ty| ty.0).unwrap(),
+                        final_arg_types[0].map(|ty| ty.1).unwrap(),
+                        None,
+                        None,
                     );
+                    err.span_label(
+                        full_call_span,
+                        format!("arguments to this {} are incorrect", call_name),
+                    );
+                    // Call out where the function is defined
+                    label_fn_like(tcx, &mut err, fn_def_id);
+                    err.emit();
+                    break 'errors;
                 }
-                TupleMatchFound::Multiple(first, last) => {
+                TupleMatchFound::Multiple(start, end) => {
+                    let mut err = tcx.sess.struct_span_err_with_code(
+                        full_call_span,
+                        &format!(
+                            "this {} takes {}{} but {} {} supplied",
+                            call_name,
+                            if c_variadic { "at least " } else { "" },
+                            potentially_plural_count(minimum_input_count, "argument"),
+                            potentially_plural_count(provided_arg_count, "argument"),
+                            if provided_arg_count == 1 { "was" } else { "were" }
+                        ),
+                        DiagnosticId::Error(err_code.to_owned()),
+                    );
+                    // Call out where the function is defined
+                    label_fn_like(tcx, &mut err, fn_def_id);
                     err.multipart_suggestion(
                         "use parentheses to construct a tuple",
-                        vec![
-                            (first.shrink_to_lo(), '('.to_string()),
-                            (last.shrink_to_hi(), ')'.to_string()),
-                        ],
+                        vec![(start, '('.to_string()), (end, ')'.to_string())],
                         Applicability::MachineApplicable,
                     );
+                    err.emit();
+                    break 'errors;
                 }
-                _ => {
-                    err.span_label(
-                        span,
-                        format!(
-                            "expected {}{}",
-                            if c_variadic { "at least " } else { "" },
-                            potentially_plural_count(expected_count, "argument")
-                        ),
+            }
+
+            // Okay, now that we've emitted the special errors separately, we
+            // are only left missing/extra/swapped and mismatched arguments, both
+            // can be collated pretty easily if needed.
+
+            // Next special case: if there is only one "Incompatible" error, just emit that
+            if errors.len() == 1 {
+                if let Some(Error::Invalid(
+                    input_idx,
+                    arg_idx,
+                    Compatibility::Incompatible(Some(error)),
+                )) = errors.iter().next()
+                {
+                    let expected_ty = expected_input_tys[*arg_idx];
+                    let provided_ty = final_arg_types[*input_idx]
+                        .map(|ty| ty.0)
+                        .unwrap_or_else(|| tcx.ty_error());
+                    let expected_ty = self.resolve_vars_if_possible(expected_ty);
+                    let provided_ty = self.resolve_vars_if_possible(provided_ty);
+                    let cause = &self.misc(provided_args[*input_idx].span);
+                    let trace = TypeTrace::types(cause, true, expected_ty, provided_ty);
+                    let mut err = self.report_and_explain_type_error(trace, error);
+                    self.emit_coerce_suggestions(
+                        &mut err,
+                        &provided_args[*input_idx],
+                        provided_ty,
+                        final_arg_types[*input_idx]
+                            .map(|ty| ty.1)
+                            .unwrap_or_else(|| tcx.ty_error()),
+                        None,
+                        None,
                     );
+                    err.span_label(
+                        full_call_span,
+                        format!("arguments to this {} are incorrect", call_name),
+                    );
+                    // Call out where the function is defined
+                    label_fn_like(tcx, &mut err, fn_def_id);
+                    err.emit();
+                    break 'errors;
                 }
             }
+
+            let mut err = if minimum_input_count == provided_arg_count {
+                struct_span_err!(
+                    tcx.sess,
+                    full_call_span,
+                    E0308,
+                    "arguments to this {} are incorrect",
+                    call_name,
+                )
+            } else {
+                tcx.sess.struct_span_err_with_code(
+                    full_call_span,
+                    &format!(
+                        "this {} takes {}{} but {} {} supplied",
+                        call_name,
+                        if c_variadic { "at least " } else { "" },
+                        potentially_plural_count(minimum_input_count, "argument"),
+                        potentially_plural_count(provided_arg_count, "argument"),
+                        if provided_arg_count == 1 { "was" } else { "were" }
+                    ),
+                    DiagnosticId::Error(err_code.to_owned()),
+                )
+            };
+
+            // As we encounter issues, keep track of what we want to provide for the suggestion
+            let mut labels = vec![];
+            // If there is a single error, we give a specific suggestion; otherwise, we change to
+            // "did you mean" with the suggested function call
+            enum SuggestionText {
+                None,
+                Provide(bool),
+                Remove(bool),
+                Swap,
+                Reorder,
+                DidYouMean,
+            }
+            let mut suggestion_text = SuggestionText::None;
+
+            let mut errors = errors.into_iter().peekable();
+            while let Some(error) = errors.next() {
+                match error {
+                    Error::Invalid(input_idx, arg_idx, compatibility) => {
+                        let expected_ty = expected_input_tys[arg_idx];
+                        let provided_ty = final_arg_types[input_idx]
+                            .map(|ty| ty.0)
+                            .unwrap_or_else(|| tcx.ty_error());
+                        let expected_ty = self.resolve_vars_if_possible(expected_ty);
+                        let provided_ty = self.resolve_vars_if_possible(provided_ty);
+                        if let Compatibility::Incompatible(error) = &compatibility {
+                            let cause = &self.misc(provided_args[input_idx].span);
+                            let trace = TypeTrace::types(cause, true, expected_ty, provided_ty);
+                            if let Some(e) = error {
+                                self.note_type_err(
+                                    &mut err,
+                                    &trace.cause,
+                                    None,
+                                    Some(trace.values),
+                                    e,
+                                    false,
+                                    true,
+                                );
+                            }
+                        }
+
+                        self.emit_coerce_suggestions(
+                            &mut err,
+                            &provided_args[input_idx],
+                            provided_ty,
+                            // FIXME(compiler-errors): expected_ty?
+                            final_arg_types[input_idx]
+                                .map(|ty| ty.1)
+                                .unwrap_or_else(|| tcx.ty_error()),
+                            None,
+                            None,
+                        );
+                    }
+                    Error::Extra(arg_idx) => {
+                        let arg_type = if let Some((_, ty)) = final_arg_types[arg_idx] {
+                            if ty.references_error() || ty.has_infer_types() {
+                                "".into()
+                            } else {
+                                format!(" of type `{}`", ty)
+                            }
+                        } else {
+                            "".into()
+                        };
+                        labels.push((
+                            provided_args[arg_idx].span,
+                            format!("argument{} unexpected", arg_type),
+                        ));
+                        suggestion_text = match suggestion_text {
+                            SuggestionText::None => SuggestionText::Remove(false),
+                            SuggestionText::Remove(_) => SuggestionText::Remove(true),
+                            _ => SuggestionText::DidYouMean,
+                        };
+                    }
+                    Error::Missing(input_idx) => {
+                        // If there are multiple missing arguments adjacent to each other,
+                        // then we can provide a single error.
+
+                        let mut missing_idxs = vec![input_idx];
+                        while let Some(e) = errors.next_if(|e| matches!(e, Error::Missing(input_idx) if *input_idx == (missing_idxs.last().unwrap() + 1))) {
+                            match e {
+                                Error::Missing(input_idx) => missing_idxs.push(input_idx),
+                                _ => unreachable!(),
+                            }
+                        }
+
+                        // NOTE: Because we might be re-arranging arguments, might have extra
+                        // arguments, etc. it's hard to *really* know where we should provide
+                        // this error label, so as a heuristic, we point to the provided arg, or
+                        // to the call if the missing inputs pass the provided args.
+                        match &missing_idxs[..] {
+                            &[input_idx] => {
+                                let expected_ty = expected_input_tys[input_idx];
+                                let input_ty = self.resolve_vars_if_possible(expected_ty);
+                                let span = if input_idx < provided_arg_count {
+                                    let arg_span = provided_args[input_idx].span;
+                                    Span::new(arg_span.lo(), arg_span.hi(), arg_span.ctxt(), None)
+                                } else {
+                                    args_span
+                                };
+                                let arg_type =
+                                    if input_ty.references_error() || input_ty.has_infer_types() {
+                                        "".into()
+                                    } else {
+                                        format!(" of type `{}`", input_ty)
+                                    };
+                                labels.push((span, format!("an argument{} is missing", arg_type)));
+                                suggestion_text = match suggestion_text {
+                                    SuggestionText::None => SuggestionText::Provide(false),
+                                    SuggestionText::Provide(_) => SuggestionText::Provide(true),
+                                    _ => SuggestionText::DidYouMean,
+                                };
+                            }
+                            &[first_idx, second_idx] => {
+                                let first_input_ty =
+                                    self.resolve_vars_if_possible(expected_input_tys[first_idx]);
+                                let second_input_ty =
+                                    self.resolve_vars_if_possible(expected_input_tys[second_idx]);
+
+                                let span = if second_idx < provided_arg_count {
+                                    let first_arg_span = provided_args[first_idx].span;
+                                    let second_arg_span = provided_args[second_idx].span;
+                                    Span::new(
+                                        first_arg_span.lo(),
+                                        second_arg_span.hi(),
+                                        first_arg_span.ctxt(),
+                                        None,
+                                    )
+                                } else {
+                                    args_span
+                                };
+                                let any_unnameable = false
+                                    || first_input_ty.references_error()
+                                    || first_input_ty.has_infer_types()
+                                    || second_input_ty.references_error()
+                                    || second_input_ty.has_infer_types();
+                                let arg_type = if any_unnameable {
+                                    "".into()
+                                } else {
+                                    format!(
+                                        " of type `{}` and `{}`",
+                                        first_input_ty, second_input_ty
+                                    )
+                                };
+                                labels
+                                    .push((span, format!("two arguments{} are missing", arg_type)));
+                                suggestion_text = match suggestion_text {
+                                    SuggestionText::None | SuggestionText::Provide(_) => {
+                                        SuggestionText::Provide(true)
+                                    }
+                                    _ => SuggestionText::DidYouMean,
+                                };
+                            }
+                            &[first_idx, second_idx, third_idx] => {
+                                let first_input_ty =
+                                    self.resolve_vars_if_possible(expected_input_tys[first_idx]);
+                                let second_input_ty =
+                                    self.resolve_vars_if_possible(expected_input_tys[second_idx]);
+                                let third_input_ty =
+                                    self.resolve_vars_if_possible(expected_input_tys[third_idx]);
+                                let span = if third_idx < provided_arg_count {
+                                    let first_arg_span = provided_args[first_idx].span;
+                                    let third_arg_span = provided_args[third_idx].span;
+                                    Span::new(
+                                        first_arg_span.lo(),
+                                        third_arg_span.hi(),
+                                        first_arg_span.ctxt(),
+                                        None,
+                                    )
+                                } else {
+                                    args_span
+                                };
+                                let any_unnameable = false
+                                    || first_input_ty.references_error()
+                                    || first_input_ty.has_infer_types()
+                                    || second_input_ty.references_error()
+                                    || second_input_ty.has_infer_types()
+                                    || third_input_ty.references_error()
+                                    || third_input_ty.has_infer_types();
+                                let arg_type = if any_unnameable {
+                                    "".into()
+                                } else {
+                                    format!(
+                                        " of type `{}`, `{}`, and `{}`",
+                                        first_input_ty, second_input_ty, third_input_ty
+                                    )
+                                };
+                                labels.push((
+                                    span,
+                                    format!("three arguments{} are missing", arg_type),
+                                ));
+                                suggestion_text = match suggestion_text {
+                                    SuggestionText::None | SuggestionText::Provide(_) => {
+                                        SuggestionText::Provide(true)
+                                    }
+                                    _ => SuggestionText::DidYouMean,
+                                };
+                            }
+                            missing_idxs => {
+                                let first_idx = *missing_idxs.first().unwrap();
+                                let last_idx = *missing_idxs.last().unwrap();
+                                // NOTE: Because we might be re-arranging arguments, might have extra arguments, etc.
+                                // It's hard to *really* know where we should provide this error label, so this is a
+                                // decent heuristic
+                                let span = if last_idx < provided_arg_count {
+                                    let first_arg_span = provided_args[first_idx].span;
+                                    let last_arg_span = provided_args[last_idx].span;
+                                    Span::new(
+                                        first_arg_span.lo(),
+                                        last_arg_span.hi(),
+                                        first_arg_span.ctxt(),
+                                        None,
+                                    )
+                                } else {
+                                    // Otherwise just label the whole function
+                                    args_span
+                                };
+                                labels.push((span, format!("multiple arguments are missing")));
+                                suggestion_text = match suggestion_text {
+                                    SuggestionText::None | SuggestionText::Provide(_) => {
+                                        SuggestionText::Provide(true)
+                                    }
+                                    _ => SuggestionText::DidYouMean,
+                                };
+                            }
+                        }
+                    }
+                    Error::Swap(input_idx, other_input_idx, arg_idx, other_arg_idx) => {
+                        let first_span = provided_args[input_idx].span;
+                        let second_span = provided_args[other_input_idx].span;
+
+                        let first_expected_ty =
+                            self.resolve_vars_if_possible(expected_input_tys[arg_idx]);
+                        let first_provided_ty = if let Some((ty, _)) = final_arg_types[input_idx] {
+                            format!(", found `{}`", ty)
+                        } else {
+                            String::new()
+                        };
+                        labels.push((
+                            first_span,
+                            format!("expected `{}`{}", first_expected_ty, first_provided_ty),
+                        ));
+                        let other_expected_ty =
+                            self.resolve_vars_if_possible(expected_input_tys[other_arg_idx]);
+                        let other_provided_ty =
+                            if let Some((ty, _)) = final_arg_types[other_input_idx] {
+                                format!(", found `{}`", ty)
+                            } else {
+                                String::new()
+                            };
+                        labels.push((
+                            second_span,
+                            format!("expected `{}`{}", other_expected_ty, other_provided_ty),
+                        ));
+                        suggestion_text = match suggestion_text {
+                            SuggestionText::None => SuggestionText::Swap,
+                            _ => SuggestionText::DidYouMean,
+                        };
+                    }
+                    Error::Permutation(args) => {
+                        for (dst_arg, dest_input) in args {
+                            let expected_ty =
+                                self.resolve_vars_if_possible(expected_input_tys[dst_arg]);
+                            let provided_ty = if let Some((ty, _)) = final_arg_types[dest_input] {
+                                format!(", found `{}`", ty)
+                            } else {
+                                String::new()
+                            };
+                            labels.push((
+                                provided_args[dest_input].span,
+                                format!("expected `{}`{}", expected_ty, provided_ty),
+                            ));
+                        }
+
+                        suggestion_text = match suggestion_text {
+                            SuggestionText::None => SuggestionText::Reorder,
+                            _ => SuggestionText::DidYouMean,
+                        };
+                    }
+                }
+            }
+
+            // If we have less than 5 things to say, it would be useful to call out exactly what's wrong
+            if labels.len() <= 5 {
+                for (span, label) in labels {
+                    err.span_label(span, label);
+                }
+            }
+
+            // Call out where the function is defined
+            label_fn_like(tcx, &mut err, fn_def_id);
+
+            // And add a suggestion block for all of the parameters
+            let suggestion_text = match suggestion_text {
+                SuggestionText::None => None,
+                SuggestionText::Provide(plural) => {
+                    Some(format!("provide the argument{}", if plural { "s" } else { "" }))
+                }
+                SuggestionText::Remove(plural) => {
+                    Some(format!("remove the extra argument{}", if plural { "s" } else { "" }))
+                }
+                SuggestionText::Swap => Some("swap these arguments".to_string()),
+                SuggestionText::Reorder => Some("reorder these arguments".to_string()),
+                SuggestionText::DidYouMean => Some("did you mean".to_string()),
+            };
+            if let Some(suggestion_text) = suggestion_text {
+                let source_map = self.sess().source_map();
+                let mut suggestion = format!(
+                    "{}(",
+                    source_map.span_to_snippet(full_call_span).unwrap_or_else(|_| String::new())
+                );
+                for (arg_index, input_idx) in matched_inputs.iter().enumerate() {
+                    let suggestion_text = if let Some(input_idx) = input_idx {
+                        let arg_span = provided_args[*input_idx].span.source_callsite();
+                        let arg_text = source_map.span_to_snippet(arg_span).unwrap();
+                        arg_text
+                    } else {
+                        // Propose a placeholder of the correct type
+                        let expected_ty = expected_input_tys[arg_index];
+                        let input_ty = self.resolve_vars_if_possible(expected_ty);
+                        if input_ty.is_unit() {
+                            "()".to_string()
+                        } else if !input_ty.is_ty_var() {
+                            format!("/* {} */", input_ty)
+                        } else {
+                            "/* value */".to_string()
+                        }
+                    };
+                    suggestion += &suggestion_text;
+                    if arg_index < minimum_input_count - 1 {
+                        suggestion += ", ";
+                    }
+                }
+                suggestion += ")";
+                err.span_suggestion_verbose(
+                    error_span,
+                    &suggestion_text,
+                    suggestion,
+                    Applicability::HasPlaceholders,
+                );
+            }
             err.emit();
         }
 
         for arg in provided_args.iter().skip(minimum_input_count) {
             let arg_ty = self.check_expr(&arg);
 
+            // If the function is c-style variadic, we skipped a bunch of arguments
+            // so we need to check those, and write out the types
+            // Ideally this would be folded into the above, for uniform style
+            // but c-variadic is already a corner case
             if c_variadic {
-                // We also need to make sure we at least write the ty of the other
-                // arguments which we skipped above, either because they were additional
-                // c_variadic args, or because we had an argument count mismatch.
-                fn variadic_error<'tcx>(sess: &'tcx Session, span: Span, ty: Ty<'tcx>, cast_ty: &str) {
+                fn variadic_error<'tcx>(
+                    sess: &'tcx Session,
+                    span: Span,
+                    ty: Ty<'tcx>,
+                    cast_ty: &str,
+                ) {
                     use crate::structured_errors::MissingCastForVariadicArg;
 
                     MissingCastForVariadicArg { sess, span, ty, cast_ty }.diagnostic().emit();
@@ -926,14 +1456,14 @@
                 err.span_suggestion_verbose(
                     span_semi,
                     "consider removing this semicolon and boxing the expression",
-                    String::new(),
+                    "",
                     Applicability::HasPlaceholders,
                 );
             } else {
                 err.span_suggestion_short(
                     span_semi,
                     "remove this semicolon",
-                    String::new(),
+                    "",
                     Applicability::MachineApplicable,
                 );
             }
@@ -1039,13 +1569,8 @@
             QPath::TypeRelative(ref qself, ref segment) => {
                 let ty = self.to_ty(qself);
 
-                let res = if let hir::TyKind::Path(QPath::Resolved(_, ref path)) = qself.kind {
-                    path.res
-                } else {
-                    Res::Err
-                };
                 let result = <dyn AstConv<'_>>::associated_path_to_ty(
-                    self, hir_id, path_span, ty, res, segment, true,
+                    self, hir_id, path_span, ty, qself, segment, true,
                 );
                 let ty = result.map(|(ty, _, _)| ty).unwrap_or_else(|_| self.tcx().ty_error());
                 let result = result.map(|(_, kind, def_id)| (kind, def_id));
@@ -1092,24 +1617,21 @@
             // Peel derived obligation, because it's the type that originally
             // started this inference chain that matters, not the one we wound
             // up with at the end.
-            fn unpeel_to_top(
-                mut code: Lrc<ObligationCauseCode<'_>>,
-            ) -> Lrc<ObligationCauseCode<'_>> {
-                let mut result_code = code.clone();
+            fn unpeel_to_top<'a, 'tcx>(
+                mut code: &'a ObligationCauseCode<'tcx>,
+            ) -> &'a ObligationCauseCode<'tcx> {
+                let mut result_code = code;
                 loop {
-                    let parent = match &*code {
-                        ObligationCauseCode::ImplDerivedObligation(c) => {
-                            c.derived.parent_code.clone()
-                        }
+                    let parent = match code {
+                        ObligationCauseCode::ImplDerivedObligation(c) => &c.derived.parent_code,
                         ObligationCauseCode::BuiltinDerivedObligation(c)
-                        | ObligationCauseCode::DerivedObligation(c) => c.parent_code.clone(),
-                        _ => break,
+                        | ObligationCauseCode::DerivedObligation(c) => &c.parent_code,
+                        _ => break result_code,
                     };
-                    result_code = std::mem::replace(&mut code, parent);
+                    (result_code, code) = (code, parent);
                 }
-                result_code
             }
-            let self_: ty::subst::GenericArg<'_> = match &*unpeel_to_top(error.obligation.cause.clone_code()) {
+            let self_: ty::subst::GenericArg<'_> = match unpeel_to_top(error.obligation.cause.code()) {
                 ObligationCauseCode::BuiltinDerivedObligation(code) |
                 ObligationCauseCode::DerivedObligation(code) => {
                     code.parent_trait_pred.self_ty().skip_binder().into()
@@ -1159,13 +1681,13 @@
                 // We make sure that only *one* argument matches the obligation failure
                 // and we assign the obligation's span to its expression's.
                 error.obligation.cause.span = args[ref_in].span;
-                let parent_code = error.obligation.cause.clone_code();
-                *error.obligation.cause.make_mut_code() =
+                error.obligation.cause.map_code(|parent_code| {
                     ObligationCauseCode::FunctionArgumentObligation {
                         arg_hir_id: args[ref_in].hir_id,
                         call_hir_id: expr.hir_id,
                         parent_code,
-                    };
+                    }
+                });
             } else if error.obligation.cause.span == call_sp {
                 // Make function calls point at the callee, not the whole thing.
                 if let hir::ExprKind::Call(callee, _) = expr.kind {
@@ -1221,3 +1743,46 @@
         }
     }
 }
+
+fn label_fn_like<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    err: &mut rustc_errors::DiagnosticBuilder<'tcx, rustc_errors::ErrorGuaranteed>,
+    def_id: Option<DefId>,
+) {
+    let Some(def_id) = def_id else {
+        return;
+    };
+
+    if let Some(def_span) = tcx.def_ident_span(def_id) {
+        let mut spans: MultiSpan = def_span.into();
+
+        let params = tcx
+            .hir()
+            .get_if_local(def_id)
+            .and_then(|node| node.body_id())
+            .into_iter()
+            .flat_map(|id| tcx.hir().body(id).params);
+
+        for param in params {
+            spans.push_span_label(param.span, String::new());
+        }
+
+        let def_kind = tcx.def_kind(def_id);
+        err.span_note(spans, &format!("{} defined here", def_kind.descr(def_id)));
+    } else {
+        match tcx.hir().get_if_local(def_id) {
+            Some(hir::Node::Expr(hir::Expr {
+                kind: hir::ExprKind::Closure { fn_decl_span, .. },
+                ..
+            })) => {
+                let spans: MultiSpan = (*fn_decl_span).into();
+
+                // Note: We don't point to param spans here because they overlap
+                // with the closure span itself
+
+                err.span_note(spans, "closure defined here");
+            }
+            _ => {}
+        }
+    }
+}
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs b/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs
index d04277b..8b680a3 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs
@@ -1,4 +1,5 @@
 mod _impl;
+mod arg_matrix;
 mod checks;
 mod suggestions;
 
@@ -114,6 +115,9 @@
     /// either given explicitly or inferred from, say, an `Fn*` trait
     /// bound. Used for diagnostic purposes only.
     pub(super) return_type_pre_known: bool,
+
+    /// True if the return type has an Opaque type
+    pub(super) return_type_has_opaque: bool,
 }
 
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
@@ -140,6 +144,7 @@
             }),
             inh,
             return_type_pre_known: true,
+            return_type_has_opaque: false,
         }
     }
 
@@ -255,7 +260,7 @@
         item_segment: &hir::PathSegment<'_>,
         poly_trait_ref: ty::PolyTraitRef<'tcx>,
     ) -> Ty<'tcx> {
-        let (trait_ref, _) = self.replace_bound_vars_with_fresh_vars(
+        let trait_ref = self.replace_bound_vars_with_fresh_vars(
             span,
             infer::LateBoundRegionConversionTime::AssocTypeProjection(item_def_id),
             poly_trait_ref,
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
index bd58a67..7195da8 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
@@ -8,15 +8,14 @@
 use rustc_hir::def::{CtorOf, DefKind};
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::{
-    Expr, ExprKind, GenericBound, ItemKind, Node, Path, QPath, Stmt, StmtKind, TyKind,
-    WherePredicate,
+    Expr, ExprKind, GenericBound, Node, Path, QPath, Stmt, StmtKind, TyKind, WherePredicate,
 };
 use rustc_infer::infer::{self, TyCtxtInferExt};
 use rustc_infer::traits;
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::subst::GenericArgKind;
-use rustc_middle::ty::{self, Binder, ToPredicate, Ty};
-use rustc_span::symbol::{kw, sym};
+use rustc_middle::ty::{self, Binder, IsSuggestable, Subst, ToPredicate, Ty};
+use rustc_span::symbol::sym;
 use rustc_span::Span;
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
 
@@ -27,7 +26,7 @@
         err.span_suggestion_short(
             span.shrink_to_hi(),
             "consider using a semicolon here",
-            ";".to_string(),
+            ";",
             Applicability::MachineApplicable,
         );
     }
@@ -46,12 +45,7 @@
         blk_id: hir::HirId,
     ) -> bool {
         let expr = expr.peel_drop_temps();
-        // If the expression is from an external macro, then do not suggest
-        // adding a semicolon, because there's nowhere to put it.
-        // See issue #81943.
-        if expr.can_have_side_effects() && !in_external_macro(self.tcx.sess, expr.span) {
-            self.suggest_missing_semicolon(err, expr, expected);
-        }
+        self.suggest_missing_semicolon(err, expr, expected, false);
         let mut pointing_at_return_type = false;
         if let Some((fn_decl, can_suggest)) = self.get_fn_decl(blk_id) {
             let fn_id = self.tcx.hir().get_return_block(blk_id).unwrap();
@@ -83,124 +77,88 @@
         expected: Ty<'tcx>,
         found: Ty<'tcx>,
     ) -> bool {
-        let hir = self.tcx.hir();
-        let (def_id, sig) = match *found.kind() {
-            ty::FnDef(def_id, _) => (def_id, found.fn_sig(self.tcx)),
-            ty::Closure(def_id, substs) => (def_id, substs.as_closure().sig()),
+        let (def_id, output, inputs) = match *found.kind() {
+            ty::FnDef(def_id, _) => {
+                let fn_sig = found.fn_sig(self.tcx);
+                (def_id, fn_sig.output(), fn_sig.inputs().skip_binder().len())
+            }
+            ty::Closure(def_id, substs) => {
+                let fn_sig = substs.as_closure().sig();
+                (def_id, fn_sig.output(), fn_sig.inputs().skip_binder().len() - 1)
+            }
+            ty::Opaque(def_id, substs) => {
+                let sig = self.tcx.bound_item_bounds(def_id).subst(self.tcx, substs).iter().find_map(|pred| {
+                    if let ty::PredicateKind::Projection(proj) = pred.kind().skip_binder()
+                    && Some(proj.projection_ty.item_def_id) == self.tcx.lang_items().fn_once_output()
+                    // args tuple will always be substs[1]
+                    && let ty::Tuple(args) = proj.projection_ty.substs.type_at(1).kind()
+                    {
+                        Some((
+                            pred.kind().rebind(proj.term.ty().unwrap()),
+                            args.len(),
+                        ))
+                    } else {
+                        None
+                    }
+                });
+                if let Some((output, inputs)) = sig {
+                    (def_id, output, inputs)
+                } else {
+                    return false;
+                }
+            }
             _ => return false,
         };
 
-        let sig = self.replace_bound_vars_with_fresh_vars(expr.span, infer::FnCall, sig).0;
-        let sig = self.normalize_associated_types_in(expr.span, sig);
-        if self.can_coerce(sig.output(), expected) {
-            let (mut sugg_call, applicability) = if sig.inputs().is_empty() {
-                (String::new(), Applicability::MachineApplicable)
-            } else {
-                ("...".to_string(), Applicability::HasPlaceholders)
+        let output = self.replace_bound_vars_with_fresh_vars(expr.span, infer::FnCall, output);
+        let output = self.normalize_associated_types_in(expr.span, output);
+        if !output.is_ty_var() && self.can_coerce(output, expected) {
+            let (sugg_call, mut applicability) = match inputs {
+                0 => ("".to_string(), Applicability::MachineApplicable),
+                1..=4 => (
+                    (0..inputs).map(|_| "_").collect::<Vec<_>>().join(", "),
+                    Applicability::MachineApplicable,
+                ),
+                _ => ("...".to_string(), Applicability::HasPlaceholders),
             };
-            let mut msg = "call this function";
-            match hir.get_if_local(def_id) {
-                Some(
-                    Node::Item(hir::Item { kind: ItemKind::Fn(.., body_id), .. })
-                    | Node::ImplItem(hir::ImplItem {
-                        kind: hir::ImplItemKind::Fn(_, body_id), ..
-                    })
-                    | Node::TraitItem(hir::TraitItem {
-                        kind: hir::TraitItemKind::Fn(.., hir::TraitFn::Provided(body_id)),
-                        ..
-                    }),
-                ) => {
-                    let body = hir.body(*body_id);
-                    sugg_call = body
-                        .params
-                        .iter()
-                        .map(|param| match &param.pat.kind {
-                            hir::PatKind::Binding(_, _, ident, None)
-                                if ident.name != kw::SelfLower =>
-                            {
-                                ident.to_string()
-                            }
-                            _ => "_".to_string(),
-                        })
-                        .collect::<Vec<_>>()
-                        .join(", ");
+
+            let msg = match self.tcx.def_kind(def_id) {
+                DefKind::Fn => "call this function",
+                DefKind::Closure | DefKind::OpaqueTy => "call this closure",
+                DefKind::Ctor(CtorOf::Struct, _) => "instantiate this tuple struct",
+                DefKind::Ctor(CtorOf::Variant, _) => "instantiate this tuple variant",
+                _ => "call this function",
+            };
+
+            let sugg = match expr.kind {
+                hir::ExprKind::Call(..)
+                | hir::ExprKind::Path(..)
+                | hir::ExprKind::Index(..)
+                | hir::ExprKind::Lit(..) => {
+                    vec![(expr.span.shrink_to_hi(), format!("({sugg_call})"))]
                 }
-                Some(Node::Expr(hir::Expr {
-                    kind: ExprKind::Closure(_, _, body_id, _, _),
-                    span: full_closure_span,
-                    ..
-                })) => {
-                    if *full_closure_span == expr.span {
-                        return false;
-                    }
-                    msg = "call this closure";
-                    let body = hir.body(*body_id);
-                    sugg_call = body
-                        .params
-                        .iter()
-                        .map(|param| match &param.pat.kind {
-                            hir::PatKind::Binding(_, _, ident, None)
-                                if ident.name != kw::SelfLower =>
-                            {
-                                ident.to_string()
-                            }
-                            _ => "_".to_string(),
-                        })
-                        .collect::<Vec<_>>()
-                        .join(", ");
+                hir::ExprKind::Closure { .. } => {
+                    // Might be `{ expr } || { bool }`
+                    applicability = Applicability::MaybeIncorrect;
+                    vec![
+                        (expr.span.shrink_to_lo(), "(".to_string()),
+                        (expr.span.shrink_to_hi(), format!(")({sugg_call})")),
+                    ]
                 }
-                Some(Node::Ctor(hir::VariantData::Tuple(fields, _))) => {
-                    sugg_call = fields.iter().map(|_| "_").collect::<Vec<_>>().join(", ");
-                    match def_id.as_local().map(|def_id| self.tcx.def_kind(def_id)) {
-                        Some(DefKind::Ctor(hir::def::CtorOf::Variant, _)) => {
-                            msg = "instantiate this tuple variant";
-                        }
-                        Some(DefKind::Ctor(CtorOf::Struct, _)) => {
-                            msg = "instantiate this tuple struct";
-                        }
-                        _ => {}
-                    }
+                _ => {
+                    vec![
+                        (expr.span.shrink_to_lo(), "(".to_string()),
+                        (expr.span.shrink_to_hi(), format!(")({sugg_call})")),
+                    ]
                 }
-                Some(Node::ForeignItem(hir::ForeignItem {
-                    kind: hir::ForeignItemKind::Fn(_, idents, _),
-                    ..
-                })) => {
-                    sugg_call = idents
-                        .iter()
-                        .map(|ident| {
-                            if ident.name != kw::SelfLower {
-                                ident.to_string()
-                            } else {
-                                "_".to_string()
-                            }
-                        })
-                        .collect::<Vec<_>>()
-                        .join(", ")
-                }
-                Some(Node::TraitItem(hir::TraitItem {
-                    kind: hir::TraitItemKind::Fn(.., hir::TraitFn::Required(idents)),
-                    ..
-                })) => {
-                    sugg_call = idents
-                        .iter()
-                        .map(|ident| {
-                            if ident.name != kw::SelfLower {
-                                ident.to_string()
-                            } else {
-                                "_".to_string()
-                            }
-                        })
-                        .collect::<Vec<_>>()
-                        .join(", ")
-                }
-                _ => {}
-            }
-            err.span_suggestion_verbose(
-                expr.span.shrink_to_hi(),
-                &format!("use parentheses to {}", msg),
-                format!("({})", sugg_call),
+            };
+
+            err.multipart_suggestion_verbose(
+                format!("use parentheses to {msg}"),
+                sugg,
                 applicability,
             );
+
             return true;
         }
         false
@@ -449,7 +407,7 @@
                         err.span_suggestion(
                             fn_name.span,
                             "use `Box::pin` to pin and box this expression",
-                            "Box::pin".to_string(),
+                            "Box::pin",
                             Applicability::MachineApplicable,
                         );
                         true
@@ -473,11 +431,15 @@
     /// This routine checks if the return expression in a block would make sense on its own as a
     /// statement and the return type has been left as default or has been specified as `()`. If so,
     /// it suggests adding a semicolon.
-    fn suggest_missing_semicolon(
+    ///
+    /// If the expression is the expression of a closure without block (`|| expr`), a
+    /// block is needed to be added too (`|| { expr; }`). This is denoted by `needs_block`.
+    pub fn suggest_missing_semicolon(
         &self,
         err: &mut Diagnostic,
         expression: &'tcx hir::Expr<'tcx>,
         expected: Ty<'tcx>,
+        needs_block: bool,
     ) {
         if expected.is_unit() {
             // `BlockTailExpression` only relevant if the tail expr would be
@@ -489,14 +451,29 @@
                 | ExprKind::If(..)
                 | ExprKind::Match(..)
                 | ExprKind::Block(..)
-                    if expression.can_have_side_effects() =>
+                    if expression.can_have_side_effects()
+                        // If the expression is from an external macro, then do not suggest
+                        // adding a semicolon, because there's nowhere to put it.
+                        // See issue #81943.
+                        && !in_external_macro(self.tcx.sess, expression.span) =>
                 {
-                    err.span_suggestion(
-                        expression.span.shrink_to_hi(),
-                        "consider using a semicolon here",
-                        ";".to_string(),
-                        Applicability::MachineApplicable,
-                    );
+                    if needs_block {
+                        err.multipart_suggestion(
+                            "consider using a semicolon here",
+                            vec![
+                                (expression.span.shrink_to_lo(), "{ ".to_owned()),
+                                (expression.span.shrink_to_hi(), "; }".to_owned()),
+                            ],
+                            Applicability::MachineApplicable,
+                        );
+                    } else {
+                        err.span_suggestion(
+                            expression.span.shrink_to_hi(),
+                            "consider using a semicolon here",
+                            ";",
+                            Applicability::MachineApplicable,
+                        );
+                    }
                 }
                 _ => (),
             }
diff --git a/compiler/rustc_typeck/src/check/generator_interior.rs b/compiler/rustc_typeck/src/check/generator_interior.rs
index be389f0..f09c7f5 100644
--- a/compiler/rustc_typeck/src/check/generator_interior.rs
+++ b/compiler/rustc_typeck/src/check/generator_interior.rs
@@ -14,28 +14,21 @@
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{Arm, Expr, ExprKind, Guard, HirId, Pat, PatKind};
 use rustc_middle::middle::region::{self, Scope, ScopeData, YieldData};
-use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty::{self, RvalueScopes, Ty, TyCtxt};
 use rustc_span::symbol::sym;
 use rustc_span::Span;
-use smallvec::SmallVec;
 use tracing::debug;
 
 mod drop_ranges;
 
 struct InteriorVisitor<'a, 'tcx> {
     fcx: &'a FnCtxt<'a, 'tcx>,
+    region_scope_tree: &'a region::ScopeTree,
     types: FxIndexSet<ty::GeneratorInteriorTypeCause<'tcx>>,
-    region_scope_tree: &'tcx region::ScopeTree,
+    rvalue_scopes: &'a RvalueScopes,
     expr_count: usize,
     kind: hir::GeneratorKind,
     prev_unresolved_span: Option<Span>,
-    /// Match arm guards have temporary borrows from the pattern bindings.
-    /// In case there is a yield point in a guard with a reference to such bindings,
-    /// such borrows can span across this yield point.
-    /// As such, we need to track these borrows and record them despite of the fact
-    /// that they may succeed the said yield point in the post-order.
-    guard_bindings: SmallVec<[SmallVec<[HirId; 4]>; 1]>,
-    guard_bindings_set: HirIdSet,
     linted_values: HirIdSet,
     drop_ranges: DropRanges,
 }
@@ -48,7 +41,6 @@
         scope: Option<region::Scope>,
         expr: Option<&'tcx Expr<'tcx>>,
         source_span: Span,
-        guard_borrowing_from_pattern: bool,
     ) {
         use rustc_span::DUMMY_SP;
 
@@ -89,8 +81,7 @@
                             // If it is a borrowing happening in the guard,
                             // it needs to be recorded regardless because they
                             // do live across this yield point.
-                            guard_borrowing_from_pattern
-                                || yield_data.expr_and_pat_count >= self.expr_count
+                            yield_data.expr_and_pat_count >= self.expr_count
                         })
                         .cloned()
                 })
@@ -189,22 +180,22 @@
     kind: hir::GeneratorKind,
 ) {
     let body = fcx.tcx.hir().body(body_id);
+    let typeck_results = fcx.inh.typeck_results.borrow();
     let mut visitor = InteriorVisitor {
         fcx,
         types: FxIndexSet::default(),
         region_scope_tree: fcx.tcx.region_scope_tree(def_id),
+        rvalue_scopes: &typeck_results.rvalue_scopes,
         expr_count: 0,
         kind,
         prev_unresolved_span: None,
-        guard_bindings: <_>::default(),
-        guard_bindings_set: <_>::default(),
         linted_values: <_>::default(),
         drop_ranges: drop_ranges::compute_drop_ranges(fcx, def_id, body),
     };
     intravisit::walk_body(&mut visitor, body);
 
     // Check that we visited the same amount of expressions as the RegionResolutionVisitor
-    let region_expr_count = visitor.region_scope_tree.body_expr_count(body_id).unwrap();
+    let region_expr_count = fcx.tcx.region_scope_tree(def_id).body_expr_count(body_id).unwrap();
     assert_eq!(region_expr_count, visitor.expr_count);
 
     // The types are already kept in insertion order.
@@ -260,8 +251,9 @@
     let witness =
         fcx.tcx.mk_generator_witness(ty::Binder::bind_with_vars(type_list, bound_vars.clone()));
 
+    drop(typeck_results);
     // Store the generator types and spans into the typeck results for this generator.
-    visitor.fcx.inh.typeck_results.borrow_mut().generator_interior_types =
+    fcx.inh.typeck_results.borrow_mut().generator_interior_types =
         ty::Binder::bind_with_vars(type_causes, bound_vars);
 
     debug!(
@@ -284,31 +276,56 @@
         let Arm { guard, pat, body, .. } = arm;
         self.visit_pat(pat);
         if let Some(ref g) = guard {
-            self.guard_bindings.push(<_>::default());
-            ArmPatCollector {
-                guard_bindings_set: &mut self.guard_bindings_set,
-                guard_bindings: self
-                    .guard_bindings
-                    .last_mut()
-                    .expect("should have pushed at least one earlier"),
+            {
+                // If there is a guard, we need to count all variables bound in the pattern as
+                // borrowed for the entire guard body, regardless of whether they are accessed.
+                // We do this by walking the pattern bindings and recording `&T` for any `x: T`
+                // that is bound.
+
+                struct ArmPatCollector<'a, 'b, 'tcx> {
+                    interior_visitor: &'a mut InteriorVisitor<'b, 'tcx>,
+                    scope: Scope,
+                }
+
+                impl<'a, 'b, 'tcx> Visitor<'tcx> for ArmPatCollector<'a, 'b, 'tcx> {
+                    fn visit_pat(&mut self, pat: &'tcx Pat<'tcx>) {
+                        intravisit::walk_pat(self, pat);
+                        if let PatKind::Binding(_, id, ident, ..) = pat.kind {
+                            let ty =
+                                self.interior_visitor.fcx.typeck_results.borrow().node_type(id);
+                            let tcx = self.interior_visitor.fcx.tcx;
+                            let ty = tcx.mk_ref(
+                                // Use `ReErased` as `resolve_interior` is going to replace all the
+                                // regions anyway.
+                                tcx.mk_region(ty::ReErased),
+                                ty::TypeAndMut { ty, mutbl: hir::Mutability::Not },
+                            );
+                            self.interior_visitor.record(
+                                ty,
+                                id,
+                                Some(self.scope),
+                                None,
+                                ident.span,
+                            );
+                        }
+                    }
+                }
+
+                ArmPatCollector {
+                    interior_visitor: self,
+                    scope: Scope { id: g.body().hir_id.local_id, data: ScopeData::Node },
+                }
+                .visit_pat(pat);
             }
-            .visit_pat(pat);
 
             match g {
                 Guard::If(ref e) => {
                     self.visit_expr(e);
                 }
-                Guard::IfLet(ref pat, ref e) => {
-                    self.visit_pat(pat);
-                    self.visit_expr(e);
+                Guard::IfLet(ref l) => {
+                    self.visit_let_expr(l);
                 }
             }
-
-            let mut scope_var_ids =
-                self.guard_bindings.pop().expect("should have pushed at least one earlier");
-            for var_id in scope_var_ids.drain(..) {
-                self.guard_bindings_set.remove(&var_id);
-            }
         }
         self.visit_expr(body);
     }
@@ -321,13 +338,11 @@
         if let PatKind::Binding(..) = pat.kind {
             let scope = self.region_scope_tree.var_scope(pat.hir_id.local_id).unwrap();
             let ty = self.fcx.typeck_results.borrow().pat_ty(pat);
-            self.record(ty, pat.hir_id, Some(scope), None, pat.span, false);
+            self.record(ty, pat.hir_id, Some(scope), None, pat.span);
         }
     }
 
     fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
-        let mut guard_borrowing_from_pattern = false;
-
         match &expr.kind {
             ExprKind::Call(callee, args) => match &callee.kind {
                 ExprKind::Path(qpath) => {
@@ -354,16 +369,6 @@
                 }
                 _ => intravisit::walk_expr(self, expr),
             },
-            ExprKind::Path(qpath) => {
-                intravisit::walk_expr(self, expr);
-                let res = self.fcx.typeck_results.borrow().qpath_res(qpath, expr.hir_id);
-                match res {
-                    Res::Local(id) if self.guard_bindings_set.contains(&id) => {
-                        guard_borrowing_from_pattern = true;
-                    }
-                    _ => {}
-                }
-            }
             _ => intravisit::walk_expr(self, expr),
         }
 
@@ -380,26 +385,21 @@
         // temporary on the stack that is live for the current temporary scope and then return a
         // reference to it. That value may be live across the entire temporary scope.
         let scope = if self.drop_ranges.is_borrowed_temporary(expr) {
-            self.region_scope_tree.temporary_scope(expr.hir_id.local_id)
+            self.rvalue_scopes.temporary_scope(self.region_scope_tree, expr.hir_id.local_id)
         } else {
             debug!("parent_node: {:?}", self.fcx.tcx.hir().find_parent_node(expr.hir_id));
             match self.fcx.tcx.hir().find_parent_node(expr.hir_id) {
                 Some(parent) => Some(Scope { id: parent.local_id, data: ScopeData::Node }),
-                None => self.region_scope_tree.temporary_scope(expr.hir_id.local_id),
+                None => {
+                    self.rvalue_scopes.temporary_scope(self.region_scope_tree, expr.hir_id.local_id)
+                }
             }
         };
 
         // If there are adjustments, then record the final type --
         // this is the actual value that is being produced.
         if let Some(adjusted_ty) = self.fcx.typeck_results.borrow().expr_ty_adjusted_opt(expr) {
-            self.record(
-                adjusted_ty,
-                expr.hir_id,
-                scope,
-                Some(expr),
-                expr.span,
-                guard_borrowing_from_pattern,
-            );
+            self.record(adjusted_ty, expr.hir_id, scope, Some(expr), expr.span);
         }
 
         // Also record the unadjusted type (which is the only type if
@@ -427,54 +427,13 @@
         // The type table might not have information for this expression
         // if it is in a malformed scope. (#66387)
         if let Some(ty) = self.fcx.typeck_results.borrow().expr_ty_opt(expr) {
-            if guard_borrowing_from_pattern {
-                // Match guards create references to all the bindings in the pattern that are used
-                // in the guard, e.g. `y if is_even(y) => ...` becomes `is_even(*r_y)` where `r_y`
-                // is a reference to `y`, so we must record a reference to the type of the binding.
-                let tcx = self.fcx.tcx;
-                let ref_ty = tcx.mk_ref(
-                    // Use `ReErased` as `resolve_interior` is going to replace all the regions anyway.
-                    tcx.mk_region(ty::ReErased),
-                    ty::TypeAndMut { ty, mutbl: hir::Mutability::Not },
-                );
-                self.record(
-                    ref_ty,
-                    expr.hir_id,
-                    scope,
-                    Some(expr),
-                    expr.span,
-                    guard_borrowing_from_pattern,
-                );
-            }
-            self.record(
-                ty,
-                expr.hir_id,
-                scope,
-                Some(expr),
-                expr.span,
-                guard_borrowing_from_pattern,
-            );
+            self.record(ty, expr.hir_id, scope, Some(expr), expr.span);
         } else {
             self.fcx.tcx.sess.delay_span_bug(expr.span, "no type for node");
         }
     }
 }
 
-struct ArmPatCollector<'a> {
-    guard_bindings_set: &'a mut HirIdSet,
-    guard_bindings: &'a mut SmallVec<[HirId; 4]>,
-}
-
-impl<'a, 'tcx> Visitor<'tcx> for ArmPatCollector<'a> {
-    fn visit_pat(&mut self, pat: &'tcx Pat<'tcx>) {
-        intravisit::walk_pat(self, pat);
-        if let PatKind::Binding(_, id, ..) = pat.kind {
-            self.guard_bindings.push(id);
-            self.guard_bindings_set.insert(id);
-        }
-    }
-}
-
 #[derive(Default)]
 pub struct SuspendCheckData<'a, 'tcx> {
     expr: Option<&'tcx Expr<'tcx>>,
diff --git a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges.rs b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges.rs
index 800232d..c2b4c47 100644
--- a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges.rs
+++ b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges.rs
@@ -41,11 +41,12 @@
     if fcx.sess().opts.debugging_opts.drop_tracking {
         let consumed_borrowed_places = find_consumed_and_borrowed(fcx, def_id, body);
 
+        let typeck_results = &fcx.typeck_results.borrow();
         let num_exprs = fcx.tcx.region_scope_tree(def_id).body_expr_count(body.id()).unwrap_or(0);
         let (mut drop_ranges, borrowed_temporaries) = build_control_flow_graph(
             fcx.tcx.hir(),
             fcx.tcx,
-            &fcx.typeck_results.borrow(),
+            typeck_results,
             consumed_borrowed_places,
             body,
             num_exprs,
diff --git a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs
index df8db0d..dbc309b 100644
--- a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs
+++ b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs
@@ -188,7 +188,7 @@
             | ExprKind::If(..)
             | ExprKind::Loop(..)
             | ExprKind::Match(..)
-            | ExprKind::Closure(..)
+            | ExprKind::Closure { .. }
             | ExprKind::Block(..)
             | ExprKind::Assign(..)
             | ExprKind::AssignOp(..)
@@ -249,6 +249,7 @@
                 | hir::Node::Stmt(..)
                 | hir::Node::PathSegment(..)
                 | hir::Node::Ty(..)
+                | hir::Node::TypeBinding(..)
                 | hir::Node::TraitRef(..)
                 | hir::Node::Binding(..)
                 | hir::Node::Pat(..)
@@ -344,9 +345,8 @@
                         // B -> C and E -> F are added implicitly due to the traversal order.
                         match guard {
                             Some(Guard::If(expr)) => self.visit_expr(expr),
-                            Some(Guard::IfLet(pat, expr)) => {
-                                self.visit_pat(pat);
-                                self.visit_expr(expr);
+                            Some(Guard::IfLet(let_expr)) => {
+                                self.visit_let_expr(let_expr);
                             }
                             None => (),
                         }
@@ -444,7 +444,7 @@
             | ExprKind::Block(..)
             | ExprKind::Box(..)
             | ExprKind::Cast(..)
-            | ExprKind::Closure(..)
+            | ExprKind::Closure { .. }
             | ExprKind::ConstBlock(..)
             | ExprKind::DropTemps(..)
             | ExprKind::Err
diff --git a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs
index e89a896..b22b791 100644
--- a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs
+++ b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs
@@ -77,38 +77,8 @@
         }
         self.places.consumed.get_mut(&consumer).map(|places| places.insert(target));
     }
-}
 
-impl<'tcx> expr_use_visitor::Delegate<'tcx> for ExprUseDelegate<'tcx> {
-    fn consume(
-        &mut self,
-        place_with_id: &expr_use_visitor::PlaceWithHirId<'tcx>,
-        diag_expr_id: HirId,
-    ) {
-        let parent = match self.tcx.hir().find_parent_node(place_with_id.hir_id) {
-            Some(parent) => parent,
-            None => place_with_id.hir_id,
-        };
-        debug!(
-            "consume {:?}; diag_expr_id={:?}, using parent {:?}",
-            place_with_id, diag_expr_id, parent
-        );
-        place_with_id
-            .try_into()
-            .map_or((), |tracked_value| self.mark_consumed(parent, tracked_value));
-    }
-
-    fn borrow(
-        &mut self,
-        place_with_id: &expr_use_visitor::PlaceWithHirId<'tcx>,
-        diag_expr_id: HirId,
-        bk: rustc_middle::ty::BorrowKind,
-    ) {
-        debug!(
-            "borrow: place_with_id = {place_with_id:?}, diag_expr_id={diag_expr_id:?}, \
-            borrow_kind={bk:?}"
-        );
-
+    fn borrow_place(&mut self, place_with_id: &expr_use_visitor::PlaceWithHirId<'tcx>) {
         self.places
             .borrowed
             .insert(TrackedValue::from_place_with_projections_allowed(place_with_id));
@@ -158,6 +128,40 @@
             self.places.borrowed_temporaries.insert(place_with_id.hir_id);
         }
     }
+}
+
+impl<'tcx> expr_use_visitor::Delegate<'tcx> for ExprUseDelegate<'tcx> {
+    fn consume(
+        &mut self,
+        place_with_id: &expr_use_visitor::PlaceWithHirId<'tcx>,
+        diag_expr_id: HirId,
+    ) {
+        let parent = match self.tcx.hir().find_parent_node(place_with_id.hir_id) {
+            Some(parent) => parent,
+            None => place_with_id.hir_id,
+        };
+        debug!(
+            "consume {:?}; diag_expr_id={:?}, using parent {:?}",
+            place_with_id, diag_expr_id, parent
+        );
+        place_with_id
+            .try_into()
+            .map_or((), |tracked_value| self.mark_consumed(parent, tracked_value));
+    }
+
+    fn borrow(
+        &mut self,
+        place_with_id: &expr_use_visitor::PlaceWithHirId<'tcx>,
+        diag_expr_id: HirId,
+        bk: rustc_middle::ty::BorrowKind,
+    ) {
+        debug!(
+            "borrow: place_with_id = {place_with_id:?}, diag_expr_id={diag_expr_id:?}, \
+            borrow_kind={bk:?}"
+        );
+
+        self.borrow_place(place_with_id);
+    }
 
     fn copy(
         &mut self,
@@ -208,9 +212,18 @@
 
     fn fake_read(
         &mut self,
-        _place: expr_use_visitor::Place<'tcx>,
-        _cause: rustc_middle::mir::FakeReadCause,
-        _diag_expr_id: HirId,
+        place_with_id: &expr_use_visitor::PlaceWithHirId<'tcx>,
+        cause: rustc_middle::mir::FakeReadCause,
+        diag_expr_id: HirId,
     ) {
+        debug!(
+            "fake_read place_with_id={place_with_id:?}; cause={cause:?}; diag_expr_id={diag_expr_id:?}"
+        );
+
+        // fake reads happen in places like the scrutinee of a match expression.
+        // we treat those as a borrow, much like a copy: the idea is that we are
+        // transiently creating a `&T` ref that we can read from to observe the current
+        // value (this `&T` is immediately dropped afterwards).
+        self.borrow_place(place_with_id);
     }
 }
diff --git a/compiler/rustc_typeck/src/check/inherited.rs b/compiler/rustc_typeck/src/check/inherited.rs
index 5cd63ca..08a64d8 100644
--- a/compiler/rustc_typeck/src/check/inherited.rs
+++ b/compiler/rustc_typeck/src/check/inherited.rs
@@ -50,6 +50,10 @@
 
     pub(super) deferred_cast_checks: RefCell<Vec<super::cast::CastCheck<'tcx>>>,
 
+    pub(super) deferred_transmute_checks: RefCell<Vec<(Ty<'tcx>, Ty<'tcx>, Span)>>,
+
+    pub(super) deferred_asm_checks: RefCell<Vec<(&'tcx hir::InlineAsm<'tcx>, hir::HirId)>>,
+
     pub(super) deferred_generator_interiors:
         RefCell<Vec<(hir::BodyId, Ty<'tcx>, hir::GeneratorKind)>>,
 
@@ -113,6 +117,8 @@
             deferred_sized_obligations: RefCell::new(Vec::new()),
             deferred_call_resolutions: RefCell::new(Default::default()),
             deferred_cast_checks: RefCell::new(Vec::new()),
+            deferred_transmute_checks: RefCell::new(Vec::new()),
+            deferred_asm_checks: RefCell::new(Vec::new()),
             deferred_generator_interiors: RefCell::new(Vec::new()),
             diverging_type_vars: RefCell::new(Default::default()),
             body_id,
diff --git a/compiler/rustc_passes/src/intrinsicck.rs b/compiler/rustc_typeck/src/check/intrinsicck.rs
similarity index 83%
rename from compiler/rustc_passes/src/intrinsicck.rs
rename to compiler/rustc_typeck/src/check/intrinsicck.rs
index 7028fc4..99a9863 100644
--- a/compiler/rustc_passes/src/intrinsicck.rs
+++ b/compiler/rustc_typeck/src/check/intrinsicck.rs
@@ -1,38 +1,17 @@
-use hir::intravisit::walk_inline_asm;
 use rustc_ast::InlineAsmTemplatePiece;
 use rustc_data_structures::stable_set::FxHashSet;
 use rustc_errors::struct_span_err;
 use rustc_hir as hir;
-use rustc_hir::def::{DefKind, Res};
-use rustc_hir::def_id::{DefId, LocalDefId};
-use rustc_hir::intravisit::{self, Visitor};
 use rustc_index::vec::Idx;
 use rustc_middle::ty::layout::{LayoutError, SizeSkeleton};
-use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::{self, FloatTy, IntTy, Ty, TyCtxt, UintTy};
+use rustc_middle::ty::{self, Article, FloatTy, IntTy, Ty, TyCtxt, TypeFoldable, UintTy};
 use rustc_session::lint;
-use rustc_span::{sym, Span, Symbol, DUMMY_SP};
+use rustc_span::{Span, Symbol, DUMMY_SP};
 use rustc_target::abi::{Pointer, VariantIdx};
-use rustc_target::asm::{InlineAsmRegOrRegClass, InlineAsmType};
-use rustc_target::spec::abi::Abi::RustIntrinsic;
+use rustc_target::asm::{InlineAsmReg, InlineAsmRegClass, InlineAsmRegOrRegClass, InlineAsmType};
+use rustc_trait_selection::infer::InferCtxtExt;
 
-fn check_mod_intrinsics(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
-    tcx.hir().visit_item_likes_in_module(module_def_id, &mut ItemVisitor { tcx }.as_deep_visitor());
-}
-
-pub fn provide(providers: &mut Providers) {
-    *providers = Providers { check_mod_intrinsics, ..*providers };
-}
-
-struct ItemVisitor<'tcx> {
-    tcx: TyCtxt<'tcx>,
-}
-
-struct ExprVisitor<'tcx> {
-    tcx: TyCtxt<'tcx>,
-    typeck_results: &'tcx ty::TypeckResults<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
-}
+use super::FnCtxt;
 
 /// If the type is `Option<T>`, it will return `T`, otherwise
 /// the type itself. Works on most `Option`-like types.
@@ -61,15 +40,15 @@
     ty
 }
 
-impl<'tcx> ExprVisitor<'tcx> {
-    fn def_id_is_transmute(&self, def_id: DefId) -> bool {
-        self.tcx.fn_sig(def_id).abi() == RustIntrinsic
-            && self.tcx.item_name(def_id) == sym::transmute
-    }
-
-    fn check_transmute(&self, span: Span, from: Ty<'tcx>, to: Ty<'tcx>) {
-        let sk_from = SizeSkeleton::compute(from, self.tcx, self.param_env);
-        let sk_to = SizeSkeleton::compute(to, self.tcx, self.param_env);
+impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
+    pub fn check_transmute(&self, span: Span, from: Ty<'tcx>, to: Ty<'tcx>) {
+        let convert = |ty: Ty<'tcx>| {
+            let ty = self.resolve_vars_if_possible(ty);
+            let ty = self.tcx.normalize_erasing_regions(self.param_env, ty);
+            (SizeSkeleton::compute(ty, self.tcx, self.param_env), ty)
+        };
+        let (sk_from, from) = convert(from);
+        let (sk_to, to) = convert(to);
 
         // Check for same size using the skeletons.
         if let (Ok(sk_from), Ok(sk_to)) = (sk_from, sk_to) {
@@ -120,8 +99,11 @@
         err.emit();
     }
 
+    // FIXME(compiler-errors): This could use `<$ty as Pointee>::Metadata == ()`
     fn is_thin_ptr_ty(&self, ty: Ty<'tcx>) -> bool {
-        if ty.is_sized(self.tcx.at(DUMMY_SP), self.param_env) {
+        // Type still may have region variables, but `Sized` does not depend
+        // on those, so just erase them before querying.
+        if self.tcx.erase_regions(ty).is_sized(self.tcx.at(DUMMY_SP), self.param_env) {
             return true;
         }
         if let ty::Foreign(..) = ty.kind() {
@@ -141,13 +123,21 @@
         target_features: &FxHashSet<Symbol>,
     ) -> Option<InlineAsmType> {
         // Check the type against the allowed types for inline asm.
-        let ty = self.typeck_results.expr_ty_adjusted(expr);
+        let ty = self.typeck_results.borrow().expr_ty_adjusted(expr);
+        let ty = self.resolve_vars_if_possible(ty);
         let asm_ty_isize = match self.tcx.sess.target.pointer_width {
             16 => InlineAsmType::I16,
             32 => InlineAsmType::I32,
             64 => InlineAsmType::I64,
             _ => unreachable!(),
         };
+
+        // Expect types to be fully resolved, no const or type variables.
+        if ty.has_infer_types_or_consts() {
+            assert!(self.is_tainted_by_errors());
+            return None;
+        }
+
         let asm_ty = match *ty.kind() {
             // `!` is allowed for input but not for output (issue #87802)
             ty::Never if is_input => return None,
@@ -197,6 +187,7 @@
                     _ => None,
                 }
             }
+            ty::Infer(_) => unreachable!(),
             _ => None,
         };
         let Some(asm_ty) = asm_ty else {
@@ -212,7 +203,7 @@
 
         // Check that the type implements Copy. The only case where this can
         // possibly fail is for SIMD types which don't #[derive(Copy)].
-        if !ty.is_copy_modulo_regions(self.tcx.at(DUMMY_SP), self.param_env) {
+        if !self.infcx.type_is_copy_modulo_regions(self.param_env, ty, DUMMY_SP) {
             let msg = "arguments for inline assembly must be copyable";
             let mut err = self.tcx.sess.struct_span_err(expr.span, msg);
             err.note(&format!("`{ty}` does not implement the Copy trait"));
@@ -232,10 +223,10 @@
             if in_asm_ty != asm_ty {
                 let msg = "incompatible types for asm inout argument";
                 let mut err = self.tcx.sess.struct_span_err(vec![in_expr.span, expr.span], msg);
-                err.span_label(
-                    in_expr.span,
-                    &format!("type `{}`", self.typeck_results.expr_ty_adjusted(in_expr)),
-                );
+
+                let in_expr_ty = self.typeck_results.borrow().expr_ty_adjusted(in_expr);
+                let in_expr_ty = self.resolve_vars_if_possible(in_expr_ty);
+                err.span_label(in_expr.span, &format!("type `{in_expr_ty}`"));
                 err.span_label(expr.span, &format!("type `{ty}`"));
                 err.note(
                     "asm inout arguments must have the same type, \
@@ -339,12 +330,14 @@
         Some(asm_ty)
     }
 
-    fn check_asm(&self, asm: &hir::InlineAsm<'tcx>, hir_id: hir::HirId) {
+    pub fn check_asm(&self, asm: &hir::InlineAsm<'tcx>, enclosing_id: hir::HirId) {
         let hir = self.tcx.hir();
-        let enclosing_id = hir.enclosing_body_owner(hir_id);
         let enclosing_def_id = hir.local_def_id(enclosing_id).to_def_id();
         let target_features = self.tcx.asm_target_features(enclosing_def_id);
-        let asm_arch = self.tcx.sess.asm_arch.unwrap();
+        let Some(asm_arch) = self.tcx.sess.asm_arch else {
+            self.tcx.sess.delay_span_bug(DUMMY_SP, "target architecture does not support asm");
+            return;
+        };
         for (idx, (op, op_sp)) in asm.operands.iter().enumerate() {
             // Validate register classes against currently enabled target
             // features. We check that at least one type is available for
@@ -360,6 +353,11 @@
                 // Some explicit registers cannot be used depending on the
                 // target. Reject those here.
                 if let InlineAsmRegOrRegClass::Reg(reg) = reg {
+                    if let InlineAsmReg::Err = reg {
+                        // `validate` will panic on `Err`, as an error must
+                        // already have been reported.
+                        continue;
+                    }
                     if let Err(msg) = reg.validate(
                         asm_arch,
                         self.tcx.sess.relocation_model(),
@@ -376,6 +374,9 @@
                 if !op.is_clobber() {
                     let mut missing_required_features = vec![];
                     let reg_class = reg.reg_class();
+                    if let InlineAsmRegClass::Err = reg_class {
+                        continue;
+                    }
                     for &(_, feature) in reg_class.supported_types(asm_arch) {
                         match feature {
                             Some(feature) => {
@@ -484,33 +485,6 @@
                         );
                     }
                 }
-                // These are checked in ItemVisitor.
-                hir::InlineAsmOperand::Const { .. }
-                | hir::InlineAsmOperand::SymFn { .. }
-                | hir::InlineAsmOperand::SymStatic { .. } => {}
-            }
-        }
-    }
-}
-
-impl<'tcx> Visitor<'tcx> for ItemVisitor<'tcx> {
-    fn visit_nested_body(&mut self, body_id: hir::BodyId) {
-        let owner_def_id = self.tcx.hir().body_owner_def_id(body_id);
-        let body = self.tcx.hir().body(body_id);
-        let param_env = self.tcx.param_env(owner_def_id.to_def_id());
-        let typeck_results = self.tcx.typeck(owner_def_id);
-        ExprVisitor { tcx: self.tcx, param_env, typeck_results }.visit_body(body);
-        self.visit_body(body);
-    }
-
-    fn visit_inline_asm(&mut self, asm: &'tcx hir::InlineAsm<'tcx>, id: hir::HirId) {
-        for (op, op_sp) in asm.operands.iter() {
-            match *op {
-                // These are checked in ExprVisitor.
-                hir::InlineAsmOperand::In { .. }
-                | hir::InlineAsmOperand::Out { .. }
-                | hir::InlineAsmOperand::InOut { .. }
-                | hir::InlineAsmOperand::SplitInOut { .. } => {}
                 // No special checking is needed for these:
                 // - Typeck has checked that Const operands are integers.
                 // - AST lowering guarantees that SymStatic points to a static.
@@ -536,31 +510,5 @@
                 }
             }
         }
-        walk_inline_asm(self, asm, id);
-    }
-}
-
-impl<'tcx> Visitor<'tcx> for ExprVisitor<'tcx> {
-    fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
-        match expr.kind {
-            hir::ExprKind::Path(ref qpath) => {
-                let res = self.typeck_results.qpath_res(qpath, expr.hir_id);
-                if let Res::Def(DefKind::Fn, did) = res
-                    && self.def_id_is_transmute(did)
-                {
-                    let typ = self.typeck_results.node_type(expr.hir_id);
-                    let sig = typ.fn_sig(self.tcx);
-                    let from = sig.inputs().skip_binder()[0];
-                    let to = sig.output().skip_binder();
-                    self.check_transmute(expr.span, from, to);
-                }
-            }
-
-            hir::ExprKind::InlineAsm(asm) => self.check_asm(asm, expr.hir_id),
-
-            _ => {}
-        }
-
-        intravisit::walk_expr(self, expr);
     }
 }
diff --git a/compiler/rustc_typeck/src/check/method/confirm.rs b/compiler/rustc_typeck/src/check/method/confirm.rs
index 7992460..4061b7c 100644
--- a/compiler/rustc_typeck/src/check/method/confirm.rs
+++ b/compiler/rustc_typeck/src/check/method/confirm.rs
@@ -572,8 +572,8 @@
 
     fn replace_bound_vars_with_fresh_vars<T>(&self, value: ty::Binder<'tcx, T>) -> T
     where
-        T: TypeFoldable<'tcx>,
+        T: TypeFoldable<'tcx> + Copy,
     {
-        self.fcx.replace_bound_vars_with_fresh_vars(self.span, infer::FnCall, value).0
+        self.fcx.replace_bound_vars_with_fresh_vars(self.span, infer::FnCall, value)
     }
 }
diff --git a/compiler/rustc_typeck/src/check/method/mod.rs b/compiler/rustc_typeck/src/check/method/mod.rs
index cb35943..5ca8221 100644
--- a/compiler/rustc_typeck/src/check/method/mod.rs
+++ b/compiler/rustc_typeck/src/check/method/mod.rs
@@ -116,7 +116,7 @@
 
     /// Adds a suggestion to call the given method to the provided diagnostic.
     #[instrument(level = "debug", skip(self, err, call_expr))]
-    crate fn suggest_method_call(
+    pub(crate) fn suggest_method_call(
         &self,
         err: &mut Diagnostic,
         msg: &str,
@@ -462,7 +462,7 @@
         // may reference those regions.
         let fn_sig = tcx.bound_fn_sig(def_id);
         let fn_sig = fn_sig.subst(self.tcx, substs);
-        let fn_sig = self.replace_bound_vars_with_fresh_vars(span, infer::FnCall, fn_sig).0;
+        let fn_sig = self.replace_bound_vars_with_fresh_vars(span, infer::FnCall, fn_sig);
 
         let InferOk { value, obligations: o } = if is_op {
             self.normalize_op_associated_types_in_as_infer_ok(span, fn_sig, opt_input_expr)
diff --git a/compiler/rustc_typeck/src/check/method/probe.rs b/compiler/rustc_typeck/src/check/method/probe.rs
index 0861d12..87254b2 100644
--- a/compiler/rustc_typeck/src/check/method/probe.rs
+++ b/compiler/rustc_typeck/src/check/method/probe.rs
@@ -681,7 +681,7 @@
     }
 
     fn assemble_inherent_candidates_for_incoherent_ty(&mut self, self_ty: Ty<'tcx>) {
-        let Some(simp) = simplify_type(self.tcx, self_ty, TreatParams::AsPlaceholders) else {
+        let Some(simp) = simplify_type(self.tcx, self_ty, TreatParams::AsInfer) else {
             bug!("unexpected incoherent type: {:?}", self_ty)
         };
         for &impl_def_id in self.tcx.incoherent_impls(simp) {
@@ -905,7 +905,7 @@
                 self.probe(|_| {
                     let substs = self.fresh_substs_for_item(self.span, method.def_id);
                     let fty = fty.subst(self.tcx, substs);
-                    let (fty, _) =
+                    let fty =
                         self.replace_bound_vars_with_fresh_vars(self.span, infer::FnCall, fty);
 
                     if let Some(self_ty) = self_ty {
diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs
index 294a42a..88800493 100644
--- a/compiler/rustc_typeck/src/check/method/suggest.rs
+++ b/compiler/rustc_typeck/src/check/method/suggest.rs
@@ -327,26 +327,22 @@
                     );
                 }
                 if let Some(span) = tcx.resolutions(()).confused_type_with_std_module.get(&span) {
-                    if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(*span) {
-                        err.span_suggestion(
-                            *span,
-                            "you are looking for the module in `std`, \
-                                     not the primitive type",
-                            format!("std::{}", snippet),
-                            Applicability::MachineApplicable,
-                        );
-                    }
+                    err.span_suggestion(
+                        span.shrink_to_lo(),
+                        "you are looking for the module in `std`, not the primitive type",
+                        "std::",
+                        Applicability::MachineApplicable,
+                    );
                 }
                 if let ty::RawPtr(_) = &actual.kind() {
                     err.note(
                         "try using `<*const T>::as_ref()` to get a reference to the \
-                                      type behind the pointer: https://doc.rust-lang.org/std/\
-                                      primitive.pointer.html#method.as_ref",
+                         type behind the pointer: https://doc.rust-lang.org/std/\
+                         primitive.pointer.html#method.as_ref",
                     );
                     err.note(
-                        "using `<*const T>::as_ref()` on a pointer \
-                                      which is unaligned or points to invalid \
-                                      or uninitialized memory is undefined behavior",
+                        "using `<*const T>::as_ref()` on a pointer which is unaligned or points \
+                         to invalid or uninitialized memory is undefined behavior",
                     );
                 }
 
@@ -457,7 +453,7 @@
                         err.span_suggestion_short(
                             span,
                             msg,
-                            String::from("len"),
+                            "len",
                             Applicability::MachineApplicable,
                         );
                     } else {
@@ -492,7 +488,7 @@
                                 Obligation {
                                     cause: cause.clone(),
                                     param_env: self.param_env,
-                                    predicate: predicate.clone(),
+                                    predicate: *predicate,
                                     recursion_depth: 0,
                                 },
                             ));
@@ -542,10 +538,10 @@
                                 };
                                 if let Some(hir::Node::Item(hir::Item { kind, .. })) = node {
                                     if let Some(g) = kind.generics() {
-                                        let key = match g.predicates {
-                                            [.., pred] => (pred.span().shrink_to_hi(), false),
-                                            [] => (g.span_for_predicates_or_empty_place(), true),
-                                        };
+                                        let key = (
+                                            g.tail_span_for_predicate_suggestion(),
+                                            g.add_where_or_trailing_comma(),
+                                        );
                                         type_params
                                             .entry(key)
                                             .or_insert_with(FxHashSet::default)
@@ -676,7 +672,7 @@
                                 let span = self_ty.span.ctxt().outer_expn_data().call_site;
                                 let mut spans: MultiSpan = span.into();
                                 spans.push_span_label(span, derive_msg.to_string());
-                                let entry = spanned_predicates.entry(spans.into());
+                                let entry = spanned_predicates.entry(spans);
                                 entry.or_insert_with(|| (path, tr_self_ty, Vec::new())).2.push(p);
                             }
 
@@ -704,7 +700,7 @@
                                     ident.span.into()
                                 };
                                 spans.push_span_label(ident.span, "in this trait".to_string());
-                                let entry = spanned_predicates.entry(spans.into());
+                                let entry = spanned_predicates.entry(spans);
                                 entry.or_insert_with(|| (path, tr_self_ty, Vec::new())).2.push(p);
                             }
 
@@ -748,7 +744,7 @@
                                 }
                                 spans.push_span_label(self_ty.span, String::new());
 
-                                let entry = spanned_predicates.entry(spans.into());
+                                let entry = spanned_predicates.entry(spans);
                                 entry.or_insert_with(|| (path, tr_self_ty, Vec::new())).2.push(p);
                             }
                             _ => {}
@@ -809,7 +805,7 @@
                         .enumerate()
                         .collect::<Vec<(usize, String)>>();
 
-                    for ((span, empty_where), obligations) in type_params.into_iter() {
+                    for ((span, add_where_or_comma), obligations) in type_params.into_iter() {
                         restrict_type_params = true;
                         // #74886: Sort here so that the output is always the same.
                         let mut obligations = obligations.into_iter().collect::<Vec<_>>();
@@ -821,11 +817,7 @@
                                  trait bound{s}",
                                 s = pluralize!(obligations.len())
                             ),
-                            format!(
-                                "{} {}",
-                                if empty_where { " where" } else { "," },
-                                obligations.join(", ")
-                            ),
+                            format!("{} {}", add_where_or_comma, obligations.join(", ")),
                             Applicability::MaybeIncorrect,
                         );
                     }
@@ -901,7 +893,7 @@
                                 item_name.span,
                                 "because of the in-memory representation of `&str`, to obtain \
                                  an `Iterator` over each of its codepoint use method `chars`",
-                                String::from("chars"),
+                                "chars",
                                 Applicability::MachineApplicable,
                             );
                         }
@@ -978,45 +970,9 @@
                     label_span_not_found(&mut err);
                 }
 
-                if let SelfSource::MethodCall(expr) = source
-                    && let Some((fields, substs)) = self.get_field_candidates(span, actual)
-                {
-                    let call_expr =
-                        self.tcx.hir().expect_expr(self.tcx.hir().get_parent_node(expr.hir_id));
-                    for candidate_field in fields.iter() {
-                        if let Some(field_path) = self.check_for_nested_field_satisfying(
-                            span,
-                            &|_, field_ty| {
-                                self.lookup_probe(
-                                    span,
-                                    item_name,
-                                    field_ty,
-                                    call_expr,
-                                    ProbeScope::AllTraits,
-                                )
-                                .is_ok()
-                            },
-                            candidate_field,
-                            substs,
-                            vec![],
-                            self.tcx.parent_module(expr.hir_id).to_def_id(),
-                        ) {
-                            let field_path_str = field_path
-                                .iter()
-                                .map(|id| id.name.to_ident_string())
-                                .collect::<Vec<String>>()
-                                .join(".");
-                            debug!("field_path_str: {:?}", field_path_str);
+                self.check_for_field_method(&mut err, source, span, actual, item_name);
 
-                            err.span_suggestion_verbose(
-                                item_name.span.shrink_to_lo(),
-                                "one of the expressions' fields has a method of the same name",
-                                format!("{field_path_str}."),
-                                Applicability::MaybeIncorrect,
-                            );
-                        }
-                    }
-                }
+                self.check_for_unwrap_self(&mut err, source, span, actual, item_name);
 
                 bound_spans.sort();
                 bound_spans.dedup();
@@ -1050,7 +1006,7 @@
                         err.span_suggestion(
                             span,
                             "there is a variant with a similar name",
-                            suggestion.to_string(),
+                            suggestion,
                             Applicability::MaybeIncorrect,
                         );
                     }
@@ -1063,12 +1019,7 @@
                         let call_expr =
                             self.tcx.hir().expect_expr(self.tcx.hir().get_parent_node(expr.hir_id));
                         if let Some(span) = call_expr.span.trim_start(expr.span) {
-                            err.span_suggestion(
-                                span,
-                                msg,
-                                String::new(),
-                                Applicability::MachineApplicable,
-                            );
+                            err.span_suggestion(span, msg, "", Applicability::MachineApplicable);
                             fallback_span = false;
                         }
                     }
@@ -1087,7 +1038,7 @@
                                 def_kind.article(),
                                 def_kind.descr(lev_candidate.def_id),
                             ),
-                            lev_candidate.name.to_string(),
+                            lev_candidate.name,
                             Applicability::MaybeIncorrect,
                         );
                     }
@@ -1208,7 +1159,7 @@
                         err.span_suggestion(
                             span,
                             "remove the arguments",
-                            String::new(),
+                            "",
                             Applicability::MaybeIncorrect,
                         );
                     }
@@ -1236,7 +1187,7 @@
             .into_iter()
             .any(|info| self.associated_value(info.def_id, item_name).is_some());
         let found_assoc = |ty: Ty<'tcx>| {
-            simplify_type(tcx, ty, TreatParams::AsPlaceholders)
+            simplify_type(tcx, ty, TreatParams::AsInfer)
                 .and_then(|simp| {
                     tcx.incoherent_impls(simp)
                         .iter()
@@ -1343,7 +1294,146 @@
         false
     }
 
-    crate fn note_unmet_impls_on_type(
+    fn check_for_field_method(
+        &self,
+        err: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>,
+        source: SelfSource<'tcx>,
+        span: Span,
+        actual: Ty<'tcx>,
+        item_name: Ident,
+    ) {
+        if let SelfSource::MethodCall(expr) = source
+            && let Some((fields, substs)) = self.get_field_candidates(span, actual)
+        {
+            let call_expr = self.tcx.hir().expect_expr(self.tcx.hir().get_parent_node(expr.hir_id));
+            for candidate_field in fields.iter() {
+                if let Some(field_path) = self.check_for_nested_field_satisfying(
+                    span,
+                    &|_, field_ty| {
+                        self.lookup_probe(
+                            span,
+                            item_name,
+                            field_ty,
+                            call_expr,
+                            ProbeScope::AllTraits,
+                        )
+                        .is_ok()
+                    },
+                    candidate_field,
+                    substs,
+                    vec![],
+                    self.tcx.parent_module(expr.hir_id).to_def_id(),
+                ) {
+                    let field_path_str = field_path
+                        .iter()
+                        .map(|id| id.name.to_ident_string())
+                        .collect::<Vec<String>>()
+                        .join(".");
+                    debug!("field_path_str: {:?}", field_path_str);
+
+                    err.span_suggestion_verbose(
+                        item_name.span.shrink_to_lo(),
+                        "one of the expressions' fields has a method of the same name",
+                        format!("{field_path_str}."),
+                        Applicability::MaybeIncorrect,
+                    );
+                }
+            }
+        }
+    }
+
+    fn check_for_unwrap_self(
+        &self,
+        err: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>,
+        source: SelfSource<'tcx>,
+        span: Span,
+        actual: Ty<'tcx>,
+        item_name: Ident,
+    ) {
+        let tcx = self.tcx;
+        let SelfSource::MethodCall(expr) = source else { return; };
+        let call_expr = tcx.hir().expect_expr(tcx.hir().get_parent_node(expr.hir_id));
+
+        let ty::Adt(kind, substs) = actual.kind() else { return; };
+        if !kind.is_enum() {
+            return;
+        }
+
+        let matching_variants: Vec<_> = kind
+            .variants()
+            .iter()
+            .flat_map(|variant| {
+                let [field] = &variant.fields[..] else { return None; };
+                let field_ty = field.ty(tcx, substs);
+
+                // Skip `_`, since that'll just lead to ambiguity.
+                if self.resolve_vars_if_possible(field_ty).is_ty_var() {
+                    return None;
+                }
+
+                self.lookup_probe(span, item_name, field_ty, call_expr, ProbeScope::AllTraits)
+                    .ok()
+                    .map(|pick| (variant, field, pick))
+            })
+            .collect();
+
+        let ret_ty_matches = |diagnostic_item| {
+            if let Some(ret_ty) = self
+                .ret_coercion
+                .as_ref()
+                .map(|c| self.resolve_vars_if_possible(c.borrow().expected_ty()))
+                && let ty::Adt(kind, _) = ret_ty.kind()
+                && tcx.get_diagnostic_item(diagnostic_item) == Some(kind.did())
+            {
+                true
+            } else {
+                false
+            }
+        };
+
+        match &matching_variants[..] {
+            [(_, field, pick)] => {
+                let self_ty = field.ty(tcx, substs);
+                err.span_note(
+                    tcx.def_span(pick.item.def_id),
+                    &format!("the method `{item_name}` exists on the type `{self_ty}`"),
+                );
+                let (article, kind, variant, question) =
+                    if Some(kind.did()) == tcx.get_diagnostic_item(sym::Result) {
+                        ("a", "Result", "Err", ret_ty_matches(sym::Result))
+                    } else if Some(kind.did()) == tcx.get_diagnostic_item(sym::Option) {
+                        ("an", "Option", "None", ret_ty_matches(sym::Option))
+                    } else {
+                        return;
+                    };
+                if question {
+                    err.span_suggestion_verbose(
+                        expr.span.shrink_to_hi(),
+                        format!(
+                            "use the `?` operator to extract the `{self_ty}` value, propagating \
+                            {article} `{kind}::{variant}` value to the caller"
+                        ),
+                        "?",
+                        Applicability::MachineApplicable,
+                    );
+                } else {
+                    err.span_suggestion_verbose(
+                        expr.span.shrink_to_hi(),
+                        format!(
+                            "consider using `{kind}::expect` to unwrap the `{self_ty}` value, \
+                             panicking if the value is {article} `{kind}::{variant}`"
+                        ),
+                        ".expect(\"REASON\")",
+                        Applicability::HasPlaceholders,
+                    );
+                }
+            }
+            // FIXME(compiler-errors): Support suggestions for other matching enum variants
+            _ => {}
+        }
+    }
+
+    pub(crate) fn note_unmet_impls_on_type(
         &self,
         err: &mut Diagnostic,
         errors: Vec<FulfillmentError<'tcx>>,
@@ -1460,7 +1550,7 @@
                             {
                                 derives.push((
                                     self_name.clone(),
-                                    self_span.clone(),
+                                    self_span,
                                     parent_diagnostic_name.to_string(),
                                 ));
                             }
@@ -1537,7 +1627,7 @@
             err.span_suggestion_verbose(
                 span.shrink_to_lo(),
                 "consider `await`ing on the `Future` and calling the method on its `Output`",
-                "await.".to_string(),
+                "await.",
                 Applicability::MaybeIncorrect,
             );
         }
@@ -1662,13 +1752,7 @@
                 (self.tcx.mk_mut_ref(self.tcx.lifetimes.re_erased, rcvr_ty), "&mut "),
                 (self.tcx.mk_imm_ref(self.tcx.lifetimes.re_erased, rcvr_ty), "&"),
             ] {
-                match self.lookup_probe(
-                    span,
-                    item_name,
-                    *rcvr_ty,
-                    rcvr,
-                    crate::check::method::probe::ProbeScope::AllTraits,
-                ) {
+                match self.lookup_probe(span, item_name, *rcvr_ty, rcvr, ProbeScope::AllTraits) {
                     Ok(pick) => {
                         // If the method is defined for the receiver we have, it likely wasn't `use`d.
                         // We point at the method, but we just skip the rest of the check for arbitrary
@@ -1700,13 +1784,15 @@
                     (self.tcx.mk_diagnostic_item(*rcvr_ty, sym::Arc), "Arc::new"),
                     (self.tcx.mk_diagnostic_item(*rcvr_ty, sym::Rc), "Rc::new"),
                 ] {
-                    if let Some(new_rcvr_t) = *rcvr_ty && let Ok(pick) = self.lookup_probe(
-                        span,
-                        item_name,
-                        new_rcvr_t,
-                        rcvr,
-                        crate::check::method::probe::ProbeScope::AllTraits,
-                    ) {
+                    if let Some(new_rcvr_t) = *rcvr_ty
+                        && let Ok(pick) = self.lookup_probe(
+                            span,
+                            item_name,
+                            new_rcvr_t,
+                            rcvr,
+                            ProbeScope::AllTraits,
+                        )
+                    {
                         debug!("try_alt_rcvr: pick candidate {:?}", pick);
                         let did = Some(pick.item.container.id());
                         // We don't want to suggest a container type when the missing
@@ -1956,7 +2042,7 @@
                 // cases where a positive bound implies a negative impl.
                 (candidates, Vec::new())
             } else if let Some(simp_rcvr_ty) =
-                simplify_type(self.tcx, rcvr_ty, TreatParams::AsBoundTypes)
+                simplify_type(self.tcx, rcvr_ty, TreatParams::AsPlaceholder)
             {
                 let mut potential_candidates = Vec::new();
                 let mut explicitly_negative = Vec::new();
@@ -1971,7 +2057,7 @@
                         .any(|imp_did| {
                             let imp = self.tcx.impl_trait_ref(imp_did).unwrap();
                             let imp_simp =
-                                simplify_type(self.tcx, imp.self_ty(), TreatParams::AsBoundTypes);
+                                simplify_type(self.tcx, imp.self_ty(), TreatParams::AsPlaceholder);
                             imp_simp.map_or(false, |s| s == simp_rcvr_ty)
                         })
                     {
diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs
index cc62144..e26f211 100644
--- a/compiler/rustc_typeck/src/check/mod.rs
+++ b/compiler/rustc_typeck/src/check/mod.rs
@@ -81,11 +81,14 @@
 mod generator_interior;
 mod inherited;
 pub mod intrinsic;
+mod intrinsicck;
 pub mod method;
 mod op;
 mod pat;
 mod place_op;
+mod region;
 mod regionck;
+pub mod rvalue_scopes;
 mod upvar;
 mod wfcheck;
 pub mod writeback;
@@ -136,6 +139,7 @@
 use crate::util::common::indenter;
 
 use self::coercion::DynamicCoerceMany;
+use self::region::region_scope_tree;
 pub use self::Expectation::*;
 
 #[macro_export]
@@ -253,6 +257,7 @@
         check_trait_item_well_formed,
         check_impl_item_well_formed,
         check_mod_item_types,
+        region_scope_tree,
         ..*providers
     };
 }
@@ -473,6 +478,9 @@
         // because they don't constrain other type variables.
         fcx.closure_analyze(body);
         assert!(fcx.deferred_call_resolutions.borrow().is_empty());
+        // Before the generator analysis, temporary scopes shall be marked to provide more
+        // precise information on types to be captured.
+        fcx.resolve_rvalue_scopes(def_id.to_def_id());
         fcx.resolve_generator_interiors(def_id.to_def_id());
 
         for (ty, span, code) in fcx.deferred_sized_obligations.borrow_mut().drain(..) {
@@ -482,6 +490,12 @@
 
         fcx.select_all_obligations_or_error();
 
+        if !fcx.infcx.is_tainted_by_errors() {
+            fcx.check_transmutes();
+        }
+
+        fcx.check_asms();
+
         if fn_sig.is_some() {
             fcx.regionck_fn(id, body, span, wf_tys);
         } else {
diff --git a/compiler/rustc_typeck/src/check/op.rs b/compiler/rustc_typeck/src/check/op.rs
index 1ae53a7..c2f97a5 100644
--- a/compiler/rustc_typeck/src/check/op.rs
+++ b/compiler/rustc_typeck/src/check/op.rs
@@ -9,15 +9,16 @@
 use rustc_middle::ty::adjustment::{
     Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability,
 };
-use rustc_middle::ty::fold::TypeFolder;
-use rustc_middle::ty::TyKind::{Adt, Array, Char, FnDef, Never, Ref, Str, Tuple, Uint};
-use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeVisitor};
+use rustc_middle::ty::{
+    self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitor,
+};
 use rustc_span::source_map::Spanned;
 use rustc_span::symbol::{sym, Ident};
 use rustc_span::Span;
 use rustc_trait_selection::infer::InferCtxtExt;
 use rustc_trait_selection::traits::error_reporting::suggestions::InferCtxtExt as _;
 use rustc_trait_selection::traits::{FulfillmentError, TraitEngine, TraitEngineExt};
+use rustc_type_ir::sty::TyKind::*;
 
 use std::ops::ControlFlow;
 
@@ -41,7 +42,23 @@
                 return_ty
             };
 
-        self.check_lhs_assignable(lhs, "E0067", op.span);
+        self.check_lhs_assignable(lhs, "E0067", op.span, |err| {
+            if let Some(lhs_deref_ty) = self.deref_once_mutably_for_diagnostic(lhs_ty) {
+                if self
+                    .lookup_op_method(
+                        lhs_deref_ty,
+                        Some(rhs_ty),
+                        Some(rhs),
+                        Op::Binary(op, IsAssign::Yes),
+                    )
+                    .is_ok()
+                {
+                    // Suppress this error, since we already emitted
+                    // a deref suggestion in check_overloaded_binop
+                    err.delay_as_bug();
+                }
+            }
+        });
 
         ty
     }
@@ -404,16 +421,16 @@
                         (err, missing_trait, use_output)
                     }
                 };
-                if let Ref(_, rty, _) = lhs_ty.kind() {
-                    if self.infcx.type_is_copy_modulo_regions(self.param_env, *rty, lhs_expr.span)
-                        && self
-                            .lookup_op_method(
-                                *rty,
-                                Some(rhs_ty),
-                                Some(rhs_expr),
-                                Op::Binary(op, is_assign),
-                            )
-                            .is_ok()
+
+                let mut suggest_deref_binop = |lhs_deref_ty: Ty<'tcx>| {
+                    if self
+                        .lookup_op_method(
+                            lhs_deref_ty,
+                            Some(rhs_ty),
+                            Some(rhs_expr),
+                            Op::Binary(op, is_assign),
+                        )
+                        .is_ok()
                     {
                         if let Ok(lstring) = source_map.span_to_snippet(lhs_expr.span) {
                             let msg = &format!(
@@ -423,17 +440,29 @@
                                     IsAssign::Yes => "=",
                                     IsAssign::No => "",
                                 },
-                                rty.peel_refs(),
+                                lhs_deref_ty.peel_refs(),
                                 lstring,
                             );
                             err.span_suggestion_verbose(
                                 lhs_expr.span.shrink_to_lo(),
                                 msg,
-                                "*".to_string(),
+                                "*",
                                 rustc_errors::Applicability::MachineApplicable,
                             );
                         }
                     }
+                };
+
+                // We should suggest `a + b` => `*a + b` if `a` is copy, and suggest
+                // `a += b` => `*a += b` if a is a mut ref.
+                if is_assign == IsAssign::Yes
+                    && let Some(lhs_deref_ty) = self.deref_once_mutably_for_diagnostic(lhs_ty) {
+                        suggest_deref_binop(lhs_deref_ty);
+                } else if is_assign == IsAssign::No
+                    && let Ref(_, lhs_deref_ty, _) = lhs_ty.kind() {
+                    if self.infcx.type_is_copy_modulo_regions(self.param_env, *lhs_deref_ty, lhs_expr.span) {
+                        suggest_deref_binop(*lhs_deref_ty);
+                    }
                 }
                 if let Some(missing_trait) = missing_trait {
                     let mut visitor = TypeParamVisitor(vec![]);
@@ -592,14 +621,14 @@
                         err.span_suggestion_verbose(
                             lhs_expr.span.until(lhs_inner_expr.span),
                             rm_borrow_msg,
-                            "".to_owned(),
+                            "",
                             Applicability::MachineApplicable
                         );
                     } else {
                         err.span_suggestion_verbose(
                             lhs_expr.span.shrink_to_hi(),
                             to_owned_msg,
-                            ".to_owned()".to_owned(),
+                            ".to_owned()",
                             Applicability::MachineApplicable
                         );
                     }
@@ -677,7 +706,7 @@
                         let predicates = errors
                             .iter()
                             .filter_map(|error| {
-                                error.obligation.predicate.clone().to_opt_poly_trait_pred()
+                                error.obligation.predicate.to_opt_poly_trait_pred()
                             });
                         for pred in predicates {
                             self.infcx.suggest_restricting_param_bound(
diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs
index 5eba95b..f45b94b 100644
--- a/compiler/rustc_typeck/src/check/pat.rs
+++ b/compiler/rustc_typeck/src/check/pat.rs
@@ -649,39 +649,41 @@
         }
     }
 
-    fn borrow_pat_suggestion(
-        &self,
-        err: &mut Diagnostic,
-        pat: &Pat<'_>,
-        inner: &Pat<'_>,
-        expected: Ty<'tcx>,
-    ) {
+    // Precondition: pat is a Ref(_) pattern
+    fn borrow_pat_suggestion(&self, err: &mut Diagnostic, pat: &Pat<'_>) {
         let tcx = self.tcx;
-        if let PatKind::Binding(..) = inner.kind {
+        if let PatKind::Ref(inner, mutbl) = pat.kind
+        && let PatKind::Binding(_, _, binding, ..) = inner.kind {
             let binding_parent_id = tcx.hir().get_parent_node(pat.hir_id);
             let binding_parent = tcx.hir().get(binding_parent_id);
-            debug!("inner {:?} pat {:?} parent {:?}", inner, pat, binding_parent);
+            debug!(?inner, ?pat, ?binding_parent);
+
+            let mutability = match mutbl {
+                ast::Mutability::Mut => "mut",
+                ast::Mutability::Not => "",
+            };
+
             match binding_parent {
-                hir::Node::Param(hir::Param { span, .. })
-                    if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(inner.span) =>
-                {
-                    err.span_suggestion(
-                        *span,
-                        &format!("did you mean `{snippet}`"),
-                        format!(" &{expected}"),
-                        Applicability::MachineApplicable,
+                // Check that there is explicit type (ie this is not a closure param with inferred type)
+                // so we don't suggest moving something to the type that does not exist
+                hir::Node::Param(hir::Param { ty_span, .. }) if binding.span != *ty_span => {
+                    err.multipart_suggestion_verbose(
+                        format!("to take parameter `{binding}` by reference, move `&{mutability}` to the type"),
+                        vec![
+                            (pat.span.until(inner.span), "".to_owned()),
+                            (ty_span.shrink_to_lo(), format!("&{}", mutbl.prefix_str())),
+                        ],
+                        Applicability::MachineApplicable
                     );
                 }
-                hir::Node::Arm(_) | hir::Node::Pat(_) => {
+                hir::Node::Param(_) | hir::Node::Arm(_) | hir::Node::Pat(_) => {
                     // rely on match ergonomics or it might be nested `&&pat`
-                    if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(inner.span) {
-                        err.span_suggestion(
-                            pat.span,
-                            "you can probably remove the explicit borrow",
-                            snippet,
-                            Applicability::MaybeIncorrect,
-                        );
-                    }
+                    err.span_suggestion_verbose(
+                        pat.span.until(inner.span),
+                        format!("consider removing `&{mutability}` from the pattern"),
+                        "",
+                        Applicability::MaybeIncorrect,
+                    );
                 }
                 _ => {} // don't provide suggestions in other cases #55175
             }
@@ -1150,14 +1152,14 @@
                     err.span_suggestion_verbose(
                         all_fields_span,
                         "use `..` to ignore all fields",
-                        String::from(".."),
+                        "..",
                         Applicability::MaybeIncorrect,
                     );
                 } else {
                     err.span_suggestion_verbose(
                         tail_span,
                         "use `..` to ignore the rest of the fields",
-                        String::from(", .."),
+                        ", ..",
                         Applicability::MaybeIncorrect,
                     );
                 }
@@ -1428,7 +1430,7 @@
         err.span_suggestion_verbose(
             sp_comma,
             "add `..` at the end of the field list to ignore all other fields",
-            sugg.to_string(),
+            sugg,
             Applicability::MachineApplicable,
         );
         err.emit();
@@ -1502,7 +1504,7 @@
                     err.span_suggestion(
                         pat_field.ident.span,
                         "a field with a similar name exists",
-                        suggested_name.to_string(),
+                        suggested_name,
                         Applicability::MaybeIncorrect,
                     );
 
@@ -1655,7 +1657,7 @@
             err.span_suggestion_verbose(
                 field.span.shrink_to_hi(),
                 "ignore the inaccessible and unused fields",
-                ", ..".to_string(),
+                ", ..",
                 Applicability::MachineApplicable,
             );
         } else {
@@ -1670,7 +1672,7 @@
             err.span_suggestion_verbose(
                 span,
                 "ignore the inaccessible and unused fields",
-                " { .. }".to_string(),
+                " { .. }",
                 Applicability::MachineApplicable,
             );
         }
@@ -1836,6 +1838,7 @@
         box_ty
     }
 
+    // Precondition: Pat is Ref(inner)
     fn check_pat_ref(
         &self,
         pat: &'tcx Pat<'tcx>,
@@ -1853,7 +1856,7 @@
 
             // Take region, inner-type from expected type if we can,
             // to avoid creating needless variables. This also helps with
-            // the bad  interactions of the given hack detailed in (note_1).
+            // the bad interactions of the given hack detailed in (note_1).
             debug!("check_pat_ref: expected={:?}", expected);
             match *expected.kind() {
                 ty::Ref(_, r_ty, r_mutbl) if r_mutbl == mutbl => (expected, r_ty),
@@ -1869,7 +1872,7 @@
                     // Look for a case like `fn foo(&foo: u32)` and suggest
                     // `fn foo(foo: &u32)`
                     if let Some(mut err) = err {
-                        self.borrow_pat_suggestion(&mut err, pat, inner, expected);
+                        self.borrow_pat_suggestion(&mut err, pat);
                         err.emit();
                     }
                     (rptr_ty, inner_ty)
diff --git a/compiler/rustc_passes/src/region.rs b/compiler/rustc_typeck/src/check/region.rs
similarity index 93%
rename from compiler/rustc_passes/src/region.rs
rename to compiler/rustc_typeck/src/check/region.rs
index d694782..9f1368a 100644
--- a/compiler/rustc_passes/src/region.rs
+++ b/compiler/rustc_typeck/src/check/region.rs
@@ -14,7 +14,6 @@
 use rustc_hir::{Arm, Block, Expr, Local, Pat, PatKind, Stmt};
 use rustc_index::vec::Idx;
 use rustc_middle::middle::region::*;
-use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::TyCtxt;
 use rustc_span::source_map;
 use rustc_span::Span;
@@ -336,7 +335,7 @@
     match expr.kind {
         // Manually recurse over closures and inline consts, because they are the only
         // case of nested bodies that share the parent environment.
-        hir::ExprKind::Closure(.., body, _, _)
+        hir::ExprKind::Closure { body, .. }
         | hir::ExprKind::ConstBlock(hir::AnonConst { body, .. }) => {
             let body = visitor.tcx.hir().body(body);
             visitor.visit_body(body);
@@ -527,7 +526,13 @@
 
         if let Some(pat) = pat {
             if is_binding_pat(pat) {
-                record_rvalue_scope(visitor, &expr, blk_scope);
+                visitor.scope_tree.record_rvalue_candidate(
+                    expr.hir_id,
+                    RvalueCandidateType::Pattern {
+                        target: expr.hir_id.local_id,
+                        lifetime: blk_scope,
+                    },
+                );
             }
         }
     }
@@ -625,9 +630,15 @@
         blk_id: Option<Scope>,
     ) {
         match expr.kind {
-            hir::ExprKind::AddrOf(_, _, ref subexpr) => {
-                record_rvalue_scope_if_borrow_expr(visitor, &subexpr, blk_id);
-                record_rvalue_scope(visitor, &subexpr, blk_id);
+            hir::ExprKind::AddrOf(_, _, subexpr) => {
+                record_rvalue_scope_if_borrow_expr(visitor, subexpr, blk_id);
+                visitor.scope_tree.record_rvalue_candidate(
+                    subexpr.hir_id,
+                    RvalueCandidateType::Borrow {
+                        target: subexpr.hir_id.local_id,
+                        lifetime: blk_id,
+                    },
+                );
             }
             hir::ExprKind::Struct(_, fields, _) => {
                 for field in fields {
@@ -647,52 +658,15 @@
                     record_rvalue_scope_if_borrow_expr(visitor, &subexpr, blk_id);
                 }
             }
-            _ => {}
-        }
-    }
-
-    /// Applied to an expression `expr` if `expr` -- or something owned or partially owned by
-    /// `expr` -- is going to be indirectly referenced by a variable in a let statement. In that
-    /// case, the "temporary lifetime" or `expr` is extended to be the block enclosing the `let`
-    /// statement.
-    ///
-    /// More formally, if `expr` matches the grammar `ET`, record the rvalue scope of the matching
-    /// `<rvalue>` as `blk_id`:
-    ///
-    /// ```text
-    ///     ET = *ET
-    ///        | ET[...]
-    ///        | ET.f
-    ///        | (ET)
-    ///        | <rvalue>
-    /// ```
-    ///
-    /// Note: ET is intended to match "rvalues or places based on rvalues".
-    fn record_rvalue_scope<'tcx>(
-        visitor: &mut RegionResolutionVisitor<'tcx>,
-        expr: &hir::Expr<'_>,
-        blk_scope: Option<Scope>,
-    ) {
-        let mut expr = expr;
-        loop {
-            // Note: give all the expressions matching `ET` with the
-            // extended temporary lifetime, not just the innermost rvalue,
-            // because in codegen if we must compile e.g., `*rvalue()`
-            // into a temporary, we request the temporary scope of the
-            // outer expression.
-            visitor.scope_tree.record_rvalue_scope(expr.hir_id.local_id, blk_scope);
-
-            match expr.kind {
-                hir::ExprKind::AddrOf(_, _, ref subexpr)
-                | hir::ExprKind::Unary(hir::UnOp::Deref, ref subexpr)
-                | hir::ExprKind::Field(ref subexpr, _)
-                | hir::ExprKind::Index(ref subexpr, _) => {
-                    expr = &subexpr;
-                }
-                _ => {
-                    return;
-                }
+            hir::ExprKind::Call(..) | hir::ExprKind::MethodCall(..) => {
+                // FIXME(@dingxiangfei2009): choose call arguments here
+                // for candidacy for extended parameter rule application
             }
+            hir::ExprKind::Index(..) => {
+                // FIXME(@dingxiangfei2009): select the indices
+                // as candidate for rvalue scope rules
+            }
+            _ => {}
         }
     }
 }
@@ -821,7 +795,14 @@
     }
 }
 
-fn region_scope_tree(tcx: TyCtxt<'_>, def_id: DefId) -> &ScopeTree {
+/// Per-body `region::ScopeTree`. The `DefId` should be the owner `DefId` for the body;
+/// in the case of closures, this will be redirected to the enclosing function.
+///
+/// Performance: This is a query rather than a simple function to enable
+/// re-use in incremental scenarios. We may sometimes need to rerun the
+/// type checker even when the HIR hasn't changed, and in those cases
+/// we can avoid reconstructing the region scope tree.
+pub fn region_scope_tree(tcx: TyCtxt<'_>, def_id: DefId) -> &ScopeTree {
     let typeck_root_def_id = tcx.typeck_root_def_id(def_id);
     if typeck_root_def_id != def_id {
         return tcx.region_scope_tree(typeck_root_def_id);
@@ -849,7 +830,3 @@
 
     tcx.arena.alloc(scope_tree)
 }
-
-pub fn provide(providers: &mut Providers) {
-    *providers = Providers { region_scope_tree, ..*providers };
-}
diff --git a/compiler/rustc_typeck/src/check/regionck.rs b/compiler/rustc_typeck/src/check/regionck.rs
index 20456cc..161ec31 100644
--- a/compiler/rustc_typeck/src/check/regionck.rs
+++ b/compiler/rustc_typeck/src/check/regionck.rs
@@ -75,7 +75,6 @@
 use crate::check::dropck;
 use crate::check::FnCtxt;
 use crate::mem_categorization as mc;
-use crate::middle::region;
 use crate::outlives::outlives_bounds::InferCtxtExt as _;
 use rustc_data_structures::stable_set::FxHashSet;
 use rustc_hir as hir;
@@ -83,7 +82,7 @@
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::PatKind;
 use rustc_infer::infer::outlives::env::OutlivesEnvironment;
-use rustc_infer::infer::{self, InferCtxt, RegionObligation, RegionckMode};
+use rustc_infer::infer::{self, InferCtxt, RegionObligation};
 use rustc_middle::hir::place::{PlaceBase, PlaceWithHirId};
 use rustc_middle::ty::adjustment;
 use rustc_middle::ty::{self, Ty};
@@ -130,6 +129,7 @@
     /// add those assumptions into the outlives-environment.
     ///
     /// Tests: `src/test/ui/regions/regions-free-region-ordering-*.rs`
+    #[instrument(level = "debug", skip(self, infcx))]
     fn add_implied_bounds<'a>(
         &mut self,
         infcx: &InferCtxt<'a, 'tcx>,
@@ -137,11 +137,8 @@
         body_id: hir::HirId,
         span: Span,
     ) {
-        debug!("add_implied_bounds()");
-
         for ty in fn_sig_tys {
             let ty = infcx.resolve_vars_if_possible(ty);
-            debug!("add_implied_bounds: ty = {}", ty);
             let implied_bounds = infcx.implied_outlives_bounds(self.param_env, body_id, ty, span);
             self.add_outlives_bounds(Some(infcx), implied_bounds)
         }
@@ -166,7 +163,8 @@
             rcx.visit_body(body);
             rcx.visit_region_obligations(id);
         }
-        rcx.resolve_regions_and_report_errors(RegionckMode::for_item_body(self.tcx));
+        // Checked by NLL
+        rcx.fcx.skip_region_resolution();
     }
 
     /// Region checking during the WF phase for items. `wf_tys` are the
@@ -178,7 +176,7 @@
         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);
-        rcx.resolve_regions_and_report_errors(RegionckMode::default());
+        rcx.resolve_regions_and_report_errors();
     }
 
     /// Region check a function body. Not invoked on closures, but
@@ -209,7 +207,8 @@
             rcx.visit_fn_body(fn_id, body, self.tcx.hir().span(fn_id));
         }
 
-        rcx.resolve_regions_and_report_errors(RegionckMode::for_item_body(self.tcx));
+        // Checked by NLL
+        rcx.fcx.skip_region_resolution();
     }
 }
 
@@ -219,8 +218,6 @@
 pub struct RegionCtxt<'a, 'tcx> {
     pub fcx: &'a FnCtxt<'a, 'tcx>,
 
-    pub region_scope_tree: &'tcx region::ScopeTree,
-
     outlives_environment: OutlivesEnvironment<'tcx>,
 
     // id of innermost fn body id
@@ -247,11 +244,9 @@
         Subject(subject): Subject,
         param_env: ty::ParamEnv<'tcx>,
     ) -> RegionCtxt<'a, 'tcx> {
-        let region_scope_tree = fcx.tcx.region_scope_tree(subject);
         let outlives_environment = OutlivesEnvironment::new(param_env);
         RegionCtxt {
             fcx,
-            region_scope_tree,
             body_id: initial_body_id,
             body_owner: subject,
             subject_def_id: subject,
@@ -368,7 +363,7 @@
         self.select_all_obligations_or_error();
     }
 
-    fn resolve_regions_and_report_errors(&self, mode: RegionckMode) {
+    fn resolve_regions_and_report_errors(&self) {
         self.infcx.process_registered_region_obligations(
             self.outlives_environment.region_bound_pairs_map(),
             Some(self.tcx.lifetimes.re_root_empty),
@@ -378,7 +373,6 @@
         self.fcx.resolve_regions_and_report_errors(
             self.subject_def_id.to_def_id(),
             &self.outlives_environment,
-            mode,
         );
     }
 
diff --git a/compiler/rustc_typeck/src/check/rvalue_scopes.rs b/compiler/rustc_typeck/src/check/rvalue_scopes.rs
new file mode 100644
index 0000000..22c9e79
--- /dev/null
+++ b/compiler/rustc_typeck/src/check/rvalue_scopes.rs
@@ -0,0 +1,83 @@
+use super::FnCtxt;
+use hir::def_id::DefId;
+use hir::Node;
+use rustc_hir as hir;
+use rustc_middle::middle::region::{RvalueCandidateType, Scope, ScopeTree};
+use rustc_middle::ty::RvalueScopes;
+
+/// Applied to an expression `expr` if `expr` -- or something owned or partially owned by
+/// `expr` -- is going to be indirectly referenced by a variable in a let statement. In that
+/// case, the "temporary lifetime" or `expr` is extended to be the block enclosing the `let`
+/// statement.
+///
+/// More formally, if `expr` matches the grammar `ET`, record the rvalue scope of the matching
+/// `<rvalue>` as `blk_id`:
+///
+/// ```text
+///     ET = *ET
+///        | ET[...]
+///        | ET.f
+///        | (ET)
+///        | <rvalue>
+/// ```
+///
+/// Note: ET is intended to match "rvalues or places based on rvalues".
+fn record_rvalue_scope_rec(
+    rvalue_scopes: &mut RvalueScopes,
+    mut expr: &hir::Expr<'_>,
+    lifetime: Option<Scope>,
+) {
+    loop {
+        // Note: give all the expressions matching `ET` with the
+        // extended temporary lifetime, not just the innermost rvalue,
+        // because in codegen if we must compile e.g., `*rvalue()`
+        // into a temporary, we request the temporary scope of the
+        // outer expression.
+
+        rvalue_scopes.record_rvalue_scope(expr.hir_id.local_id, lifetime);
+
+        match expr.kind {
+            hir::ExprKind::AddrOf(_, _, subexpr)
+            | hir::ExprKind::Unary(hir::UnOp::Deref, subexpr)
+            | hir::ExprKind::Field(subexpr, _)
+            | hir::ExprKind::Index(subexpr, _) => {
+                expr = subexpr;
+            }
+            _ => {
+                return;
+            }
+        }
+    }
+}
+fn record_rvalue_scope(
+    rvalue_scopes: &mut RvalueScopes,
+    expr: &hir::Expr<'_>,
+    candidate: &RvalueCandidateType,
+) {
+    debug!("resolve_rvalue_scope(expr={expr:?}, candidate={candidate:?})");
+    match candidate {
+        RvalueCandidateType::Borrow { lifetime, .. }
+        | RvalueCandidateType::Pattern { lifetime, .. } => {
+            record_rvalue_scope_rec(rvalue_scopes, expr, *lifetime)
+        } // FIXME(@dingxiangfei2009): handle the candidates in the function call arguments
+    }
+}
+
+pub fn resolve_rvalue_scopes<'a, 'tcx>(
+    fcx: &'a FnCtxt<'a, 'tcx>,
+    scope_tree: &'a ScopeTree,
+    def_id: DefId,
+) -> RvalueScopes {
+    let tcx = &fcx.tcx;
+    let hir_map = tcx.hir();
+    let mut rvalue_scopes = RvalueScopes::new();
+    debug!("start resolving rvalue scopes, def_id={def_id:?}");
+    debug!("rvalue_scope: rvalue_candidates={:?}", scope_tree.rvalue_candidates);
+    for (&hir_id, candidate) in &scope_tree.rvalue_candidates {
+        let Some(Node::Expr(expr)) = hir_map.find(hir_id) else {
+            bug!("hir node does not exist")
+        };
+        record_rvalue_scope(&mut rvalue_scopes, expr, candidate);
+    }
+    rvalue_scopes
+}
diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs
index fee2efd..0837d9c 100644
--- a/compiler/rustc_typeck/src/check/upvar.rs
+++ b/compiler/rustc_typeck/src/check/upvar.rs
@@ -142,10 +142,10 @@
 impl<'a, 'tcx> Visitor<'tcx> for InferBorrowKindVisitor<'a, 'tcx> {
     fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
         match expr.kind {
-            hir::ExprKind::Closure(cc, _, body_id, _, _) => {
+            hir::ExprKind::Closure { capture_clause, body: body_id, .. } => {
                 let body = self.fcx.tcx.hir().body(body_id);
                 self.visit_body(body);
-                self.fcx.analyze_closure(expr.hir_id, expr.span, body_id, body, cc);
+                self.fcx.analyze_closure(expr.hir_id, expr.span, body_id, body, capture_clause);
             }
             hir::ExprKind::ConstBlock(anon_const) => {
                 let body = self.fcx.tcx.hir().body(anon_const.body);
@@ -1755,14 +1755,19 @@
 }
 
 impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> {
-    fn fake_read(&mut self, place: Place<'tcx>, cause: FakeReadCause, diag_expr_id: hir::HirId) {
-        let PlaceBase::Upvar(_) = place.base else { return };
+    fn fake_read(
+        &mut self,
+        place: &PlaceWithHirId<'tcx>,
+        cause: FakeReadCause,
+        diag_expr_id: hir::HirId,
+    ) {
+        let PlaceBase::Upvar(_) = place.place.base else { return };
 
         // We need to restrict Fake Read precision to avoid fake reading unsafe code,
         // such as deref of a raw pointer.
         let dummy_capture_kind = ty::UpvarCapture::ByRef(ty::BorrowKind::ImmBorrow);
 
-        let (place, _) = restrict_capture_precision(place, dummy_capture_kind);
+        let (place, _) = restrict_capture_precision(place.place.clone(), dummy_capture_kind);
 
         let (place, _) = restrict_repr_packed_field_ref_capture(
             self.fcx.tcx,
@@ -2034,7 +2039,7 @@
 /// - s2: Comma separated names of the variables being migrated.
 fn migration_suggestion_for_2229(
     tcx: TyCtxt<'_>,
-    need_migrations: &Vec<NeededMigration>,
+    need_migrations: &[NeededMigration],
 ) -> (String, String) {
     let need_migrations_variables = need_migrations
         .iter()
diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs
index 5096686..7931215 100644
--- a/compiler/rustc_typeck/src/check/wfcheck.rs
+++ b/compiler/rustc_typeck/src/check/wfcheck.rs
@@ -15,14 +15,13 @@
 use rustc_infer::infer::outlives::env::OutlivesEnvironment;
 use rustc_infer::infer::outlives::obligations::TypeOutlives;
 use rustc_infer::infer::region_constraints::GenericKind;
-use rustc_infer::infer::{self, RegionckMode};
-use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
+use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt};
 use rustc_middle::hir::nested_filter;
 use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts, Subst};
 use rustc_middle::ty::trait_def::TraitSpecializationKind;
 use rustc_middle::ty::{
     self, AdtKind, EarlyBinder, GenericParamDefKind, ToPredicate, Ty, TyCtxt, TypeFoldable,
-    TypeVisitor,
+    TypeSuperFoldable, TypeVisitor,
 };
 use rustc_session::parse::feature_err;
 use rustc_span::symbol::{sym, Ident, Symbol};
@@ -30,9 +29,9 @@
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
 use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode, WellFormedLoc};
 
+use std::cell::LazyCell;
 use std::convert::TryInto;
 use std::iter;
-use std::lazy::Lazy;
 use std::ops::ControlFlow;
 
 /// Helper type of a temporary returned by `.for_item(...)`.
@@ -41,7 +40,7 @@
 /// ```ignore (illustrative)
 /// F: for<'b, 'tcx> where 'tcx FnOnce(FnCtxt<'b, 'tcx>)
 /// ```
-struct CheckWfFcxBuilder<'tcx> {
+pub(super) struct CheckWfFcxBuilder<'tcx> {
     inherited: super::InheritedBuilder<'tcx>,
     id: hir::HirId,
     span: Span,
@@ -49,7 +48,7 @@
 }
 
 impl<'tcx> CheckWfFcxBuilder<'tcx> {
-    fn with_fcx<F>(&mut self, f: F)
+    pub(super) fn with_fcx<F>(&mut self, f: F)
     where
         F: for<'b> FnOnce(&FnCtxt<'b, 'tcx>) -> FxHashSet<Ty<'tcx>>,
     {
@@ -421,7 +420,7 @@
 
             let suggestion = format!(
                 "{} {}",
-                if !gat_item_hir.generics.predicates.is_empty() { "," } else { " where" },
+                gat_item_hir.generics.add_where_or_trailing_comma(),
                 unsatisfied_bounds.join(", "),
             );
             err.span_suggestion(
@@ -491,7 +490,7 @@
     // The bounds we that we would require from `to_check`
     let mut bounds = FxHashSet::default();
 
-    let (regions, types) = GATSubstCollector::visit(tcx, gat_def_id.to_def_id(), to_check);
+    let (regions, types) = GATSubstCollector::visit(gat_def_id.to_def_id(), to_check);
 
     // If both regions and types are empty, then this GAT isn't in the
     // set of types we are checking, and we shouldn't try to do clause analysis
@@ -650,11 +649,7 @@
 
         add_constraints(&infcx, region_bound_pairs);
 
-        let errors = infcx.resolve_regions(
-            id.expect_owner().to_def_id(),
-            &outlives_environment,
-            RegionckMode::default(),
-        );
+        let errors = infcx.resolve_regions(id.expect_owner().to_def_id(), &outlives_environment);
 
         debug!(?errors, "errors");
 
@@ -669,7 +664,6 @@
 /// the two vectors, `regions` and `types` (depending on their kind). For each
 /// parameter `Pi` also track the index `i`.
 struct GATSubstCollector<'tcx> {
-    tcx: TyCtxt<'tcx>,
     gat: DefId,
     // Which region appears and which parameter index its substituted for
     regions: FxHashSet<(ty::Region<'tcx>, usize)>,
@@ -679,16 +673,11 @@
 
 impl<'tcx> GATSubstCollector<'tcx> {
     fn visit<T: TypeFoldable<'tcx>>(
-        tcx: TyCtxt<'tcx>,
         gat: DefId,
         t: T,
     ) -> (FxHashSet<(ty::Region<'tcx>, usize)>, FxHashSet<(Ty<'tcx>, usize)>) {
-        let mut visitor = GATSubstCollector {
-            tcx,
-            gat,
-            regions: FxHashSet::default(),
-            types: FxHashSet::default(),
-        };
+        let mut visitor =
+            GATSubstCollector { gat, regions: FxHashSet::default(), types: FxHashSet::default() };
         t.visit_with(&mut visitor);
         (visitor.regions, visitor.types)
     }
@@ -697,19 +686,12 @@
 impl<'tcx> TypeVisitor<'tcx> for GATSubstCollector<'tcx> {
     type BreakTy = !;
 
-    fn visit_binder<T: TypeFoldable<'tcx>>(
-        &mut self,
-        t: &ty::Binder<'tcx, T>,
-    ) -> ControlFlow<Self::BreakTy> {
-        self.tcx.liberate_late_bound_regions(self.gat, t.clone()).visit_with(self)
-    }
-
     fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
         match t.kind() {
             ty::Projection(p) if p.item_def_id == self.gat => {
                 for (idx, subst) in p.substs.iter().enumerate() {
                     match subst.unpack() {
-                        GenericArgKind::Lifetime(lt) => {
+                        GenericArgKind::Lifetime(lt) if !lt.is_late_bound() => {
                             self.regions.insert((lt, idx));
                         }
                         GenericArgKind::Type(t) => {
@@ -827,7 +809,9 @@
                     );
                 }
 
-                if traits::search_for_structural_match_violation(param.span, tcx, ty).is_some() {
+                if let Some(non_structural_match_ty) =
+                    traits::search_for_structural_match_violation(param.span, tcx, ty)
+                {
                     // We use the same error code in both branches, because this is really the same
                     // issue: we just special-case the message for type parameters to make it
                     // clearer.
@@ -853,19 +837,23 @@
                         )
                         .emit();
                     } else {
-                        struct_span_err!(
+                        let mut diag = struct_span_err!(
                             tcx.sess,
                             hir_ty.span,
                             E0741,
                             "`{}` must be annotated with `#[derive(PartialEq, Eq)]` to be used as \
                             the type of a const parameter",
-                            ty,
-                        )
-                        .span_label(
-                            hir_ty.span,
-                            format!("`{ty}` doesn't derive both `PartialEq` and `Eq`"),
-                        )
-                        .emit();
+                            non_structural_match_ty.ty,
+                        );
+
+                        if ty == non_structural_match_ty.ty {
+                            diag.span_label(
+                                hir_ty.span,
+                                format!("`{ty}` doesn't derive both `PartialEq` and `Eq`"),
+                            );
+                        }
+
+                        diag.emit();
                     }
                 }
             } else {
@@ -966,7 +954,7 @@
     })
 }
 
-fn for_item<'tcx>(tcx: TyCtxt<'tcx>, item: &hir::Item<'_>) -> CheckWfFcxBuilder<'tcx> {
+pub(super) fn for_item<'tcx>(tcx: TyCtxt<'tcx>, item: &hir::Item<'_>) -> CheckWfFcxBuilder<'tcx> {
     for_id(tcx, item.def_id, item.span)
 }
 
@@ -1222,7 +1210,7 @@
                     fcx.body_id,
                     &trait_ref,
                     ast_trait_ref.path.span,
-                    Some(item),
+                    item,
                 );
                 debug!(?obligations);
                 for obligation in obligations {
@@ -1381,7 +1369,7 @@
                 }
 
                 fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
-                    if let ty::ConstKind::Param(param) = c.val() {
+                    if let ty::ConstKind::Param(param) = c.kind() {
                         self.params.insert(param.index);
                     }
                     c.super_visit_with(self)
@@ -1727,7 +1715,7 @@
     identify_constrained_generic_params(tcx, ty_predicates, None, &mut constrained_parameters);
 
     // Lazily calculated because it is only needed in case of an error.
-    let explicitly_bounded_params = Lazy::new(|| {
+    let explicitly_bounded_params = LazyCell::new(|| {
         let icx = crate::collect::ItemCtxt::new(tcx, item.def_id.to_def_id());
         hir_generics
             .predicates
diff --git a/compiler/rustc_typeck/src/check/writeback.rs b/compiler/rustc_typeck/src/check/writeback.rs
index 72a50d0..9459cf5 100644
--- a/compiler/rustc_typeck/src/check/writeback.rs
+++ b/compiler/rustc_typeck/src/check/writeback.rs
@@ -14,7 +14,7 @@
 use rustc_middle::hir::place::Place as HirPlace;
 use rustc_middle::mir::FakeReadCause;
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCast};
-use rustc_middle::ty::fold::{TypeFoldable, TypeFolder};
+use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
 use rustc_middle::ty::{self, ClosureSizeProfileData, Ty, TyCtxt};
 use rustc_span::symbol::sym;
 use rustc_span::Span;
@@ -71,6 +71,9 @@
         wbcx.visit_user_provided_sigs();
         wbcx.visit_generator_interior_types();
 
+        wbcx.typeck_results.rvalue_scopes =
+            mem::take(&mut self.typeck_results.borrow_mut().rvalue_scopes);
+
         let used_trait_imports =
             mem::take(&mut self.typeck_results.borrow_mut().used_trait_imports);
         debug!("used_trait_imports({:?}) = {:?}", item_def_id, used_trait_imports);
@@ -258,10 +261,8 @@
         self.fix_scalar_builtin_expr(e);
         self.fix_index_builtin_expr(e);
 
-        self.visit_node_id(e.span, e.hir_id);
-
         match e.kind {
-            hir::ExprKind::Closure(_, _, body, _, _) => {
+            hir::ExprKind::Closure { body, .. } => {
                 let body = self.fcx.tcx.hir().body(body);
                 for param in body.params {
                     self.visit_node_id(e.span, param.hir_id);
@@ -286,6 +287,7 @@
             _ => {}
         }
 
+        self.visit_node_id(e.span, e.hir_id);
         intravisit::walk_expr(self, e);
     }
 
@@ -646,7 +648,7 @@
     }
 }
 
-crate trait Locatable {
+pub(crate) trait Locatable {
     fn to_span(&self, tcx: TyCtxt<'_>) -> Span;
 }
 
diff --git a/compiler/rustc_typeck/src/check_unused.rs b/compiler/rustc_typeck/src/check_unused.rs
index 00f0d1e..4a3cfa1 100644
--- a/compiler/rustc_typeck/src/check_unused.rs
+++ b/compiler/rustc_typeck/src/check_unused.rs
@@ -16,48 +16,32 @@
         used_trait_imports.extend(imports.iter());
     }
 
-    for id in tcx.hir().items() {
-        if matches!(tcx.def_kind(id.def_id), DefKind::Use) {
-            if tcx.visibility(id.def_id).is_public() {
-                continue;
-            }
-            let item = tcx.hir().item(id);
-            if item.span.is_dummy() {
-                continue;
-            }
-            if let hir::ItemKind::Use(path, _) = item.kind {
-                check_import(tcx, &mut used_trait_imports, item.item_id(), path.span);
-            }
+    for &id in tcx.maybe_unused_trait_imports(()) {
+        debug_assert_eq!(tcx.def_kind(id), DefKind::Use);
+        if tcx.visibility(id).is_public() {
+            continue;
         }
+        if used_trait_imports.contains(&id) {
+            continue;
+        }
+        let item = tcx.hir().expect_item(id);
+        if item.span.is_dummy() {
+            continue;
+        }
+        let hir::ItemKind::Use(path, _) = item.kind else { unreachable!() };
+        tcx.struct_span_lint_hir(lint::builtin::UNUSED_IMPORTS, item.hir_id(), path.span, |lint| {
+            let msg = if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(path.span) {
+                format!("unused import: `{}`", snippet)
+            } else {
+                "unused import".to_owned()
+            };
+            lint.build(&msg).emit();
+        });
     }
 
     unused_crates_lint(tcx);
 }
 
-fn check_import<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    used_trait_imports: &mut FxHashSet<LocalDefId>,
-    item_id: hir::ItemId,
-    span: Span,
-) {
-    if !tcx.maybe_unused_trait_import(item_id.def_id) {
-        return;
-    }
-
-    if used_trait_imports.contains(&item_id.def_id) {
-        return;
-    }
-
-    tcx.struct_span_lint_hir(lint::builtin::UNUSED_IMPORTS, item_id.hir_id(), span, |lint| {
-        let msg = if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(span) {
-            format!("unused import: `{}`", snippet)
-        } else {
-            "unused import".to_owned()
-        };
-        lint.build(&msg).emit();
-    });
-}
-
 fn unused_crates_lint(tcx: TyCtxt<'_>) {
     let lint = lint::builtin::UNUSED_EXTERN_CRATES;
 
@@ -138,7 +122,7 @@
                         .span_suggestion_short(
                             span_with_attrs,
                             "remove it",
-                            String::new(),
+                            "",
                             Applicability::MachineApplicable,
                         )
                         .emit();
diff --git a/compiler/rustc_typeck/src/coherence/builtin.rs b/compiler/rustc_typeck/src/coherence/builtin.rs
index 3135e99..c647c2a 100644
--- a/compiler/rustc_typeck/src/coherence/builtin.rs
+++ b/compiler/rustc_typeck/src/coherence/builtin.rs
@@ -2,21 +2,21 @@
 //! up data structures required by type-checking/codegen.
 
 use crate::errors::{CopyImplOnNonAdt, CopyImplOnTypeWithDtor, DropImplOnWrongItem};
-use rustc_errors::struct_span_err;
+use rustc_errors::{struct_span_err, MultiSpan};
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::ItemKind;
 use rustc_infer::infer;
 use rustc_infer::infer::outlives::env::OutlivesEnvironment;
-use rustc_infer::infer::{RegionckMode, TyCtxtInferExt};
+use rustc_infer::infer::TyCtxtInferExt;
 use rustc_middle::ty::adjustment::CoerceUnsizedInfo;
-use rustc_middle::ty::TypeFoldable;
-use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty::{self, suggest_constraining_type_params, Ty, TyCtxt, TypeFoldable};
 use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
 use rustc_trait_selection::traits::misc::{can_type_implement_copy, CopyImplementationError};
 use rustc_trait_selection::traits::predicate_for_trait_def;
 use rustc_trait_selection::traits::{self, ObligationCause, TraitEngine, TraitEngineExt};
+use std::collections::BTreeMap;
 
 pub fn check_trait(tcx: TyCtxt<'_>, trait_def_id: DefId) {
     let lang_items = tcx.lang_items();
@@ -91,8 +91,26 @@
                 E0204,
                 "the trait `Copy` may not be implemented for this type"
             );
+
+            // We'll try to suggest constraining type parameters to fulfill the requirements of
+            // their `Copy` implementation.
+            let mut generics = None;
+            if let ty::Adt(def, _substs) = self_type.kind() {
+                let self_def_id = def.did();
+                if let Some(local) = self_def_id.as_local() {
+                    let self_item = tcx.hir().expect_item(local);
+                    generics = self_item.kind.generics();
+                }
+            }
+            let mut errors: BTreeMap<_, Vec<_>> = Default::default();
+            let mut bounds = vec![];
+
             for (field, ty) in fields {
                 let field_span = tcx.def_span(field.did);
+                let field_ty_span = match tcx.hir().get_if_local(field.did) {
+                    Some(hir::Node::Field(field_def)) => field_def.ty.span,
+                    _ => field_span,
+                };
                 err.span_label(field_span, "this field does not implement `Copy`");
                 // Spin up a new FulfillmentContext, so we can get the _precise_ reason
                 // why this field does not implement Copy. This is useful because sometimes
@@ -105,7 +123,7 @@
                         param_env,
                         ty,
                         tcx.lang_items().copy_trait().unwrap(),
-                        traits::ObligationCause::dummy_with_span(field_span),
+                        traits::ObligationCause::dummy_with_span(field_ty_span),
                     );
                     for error in fulfill_cx.select_all_or_error(&infcx) {
                         let error_predicate = error.obligation.predicate;
@@ -115,17 +133,46 @@
                         // FIXME: This error could be more descriptive, especially if the error_predicate
                         // contains a foreign type or if it's a deeply nested type...
                         if error_predicate != error.root_obligation.predicate {
-                            err.span_note(
-                                error.obligation.cause.span,
-                                &format!(
-                                    "the `Copy` impl for `{}` requires that `{}`",
-                                    ty, error_predicate
-                                ),
-                            );
+                            errors
+                                .entry((ty.to_string(), error_predicate.to_string()))
+                                .or_default()
+                                .push(error.obligation.cause.span);
+                        }
+                        if let ty::PredicateKind::Trait(ty::TraitPredicate {
+                            trait_ref,
+                            polarity: ty::ImplPolarity::Positive,
+                            ..
+                        }) = error_predicate.kind().skip_binder()
+                        {
+                            let ty = trait_ref.self_ty();
+                            if let ty::Param(_) = ty.kind() {
+                                bounds.push((
+                                    format!("{ty}"),
+                                    trait_ref.print_only_trait_path().to_string(),
+                                    Some(trait_ref.def_id),
+                                ));
+                            }
                         }
                     }
                 });
             }
+            for ((ty, error_predicate), spans) in errors {
+                let span: MultiSpan = spans.into();
+                err.span_note(
+                    span,
+                    &format!("the `Copy` impl for `{}` requires that `{}`", ty, error_predicate),
+                );
+            }
+            if let Some(generics) = generics {
+                suggest_constraining_type_params(
+                    tcx,
+                    generics,
+                    &mut err,
+                    bounds.iter().map(|(param, constraint, def_id)| {
+                        (param.as_str(), constraint.as_str(), *def_id)
+                    }),
+                );
+            }
             err.emit();
         }
         Err(CopyImplementationError::NotAnAdt) => {
@@ -177,7 +224,7 @@
     tcx.infer_ctxt().enter(|infcx| {
         let cause = ObligationCause::misc(span, impl_hir_id);
 
-        use ty::TyKind::*;
+        use rustc_type_ir::sty::TyKind::*;
         match (source.kind(), target.kind()) {
             (&Ref(r_a, _, mutbl_a), Ref(r_b, _, mutbl_b))
                 if infcx.at(&cause, param_env).eq(r_a, *r_b).is_ok() && mutbl_a == *mutbl_b => {}
@@ -302,11 +349,7 @@
 
                     // Finally, resolve all regions.
                     let outlives_env = OutlivesEnvironment::new(param_env);
-                    infcx.resolve_regions_and_report_errors(
-                        impl_did.to_def_id(),
-                        &outlives_env,
-                        RegionckMode::default(),
-                    );
+                    infcx.resolve_regions_and_report_errors(impl_did.to_def_id(), &outlives_env);
                 }
             }
             _ => {
@@ -563,11 +606,7 @@
 
         // Finally, resolve all regions.
         let outlives_env = OutlivesEnvironment::new(param_env);
-        infcx.resolve_regions_and_report_errors(
-            impl_did.to_def_id(),
-            &outlives_env,
-            RegionckMode::default(),
-        );
+        infcx.resolve_regions_and_report_errors(impl_did.to_def_id(), &outlives_env);
 
         CoerceUnsizedInfo { custom_kind: kind }
     })
diff --git a/compiler/rustc_typeck/src/coherence/inherent_impls.rs b/compiler/rustc_typeck/src/coherence/inherent_impls.rs
index b9d4167..7a9b874 100644
--- a/compiler/rustc_typeck/src/coherence/inherent_impls.rs
+++ b/compiler/rustc_typeck/src/coherence/inherent_impls.rs
@@ -104,7 +104,7 @@
                 }
             }
 
-            if let Some(simp) = simplify_type(self.tcx, self_ty, TreatParams::AsPlaceholders) {
+            if let Some(simp) = simplify_type(self.tcx, self_ty, TreatParams::AsInfer) {
                 self.impls_map.incoherent_impls.entry(simp).or_default().push(impl_def_id);
             } else {
                 bug!("unexpected self type: {:?}", self_ty);
@@ -169,7 +169,7 @@
             }
         }
 
-        if let Some(simp) = simplify_type(self.tcx, ty, TreatParams::AsPlaceholders) {
+        if let Some(simp) = simplify_type(self.tcx, ty, TreatParams::AsInfer) {
             self.impls_map.incoherent_impls.entry(simp).or_default().push(impl_def_id);
         } else {
             bug!("unexpected primitive type: {:?}", ty);
diff --git a/compiler/rustc_typeck/src/coherence/mod.rs b/compiler/rustc_typeck/src/coherence/mod.rs
index 3f1b4828..3903448 100644
--- a/compiler/rustc_typeck/src/coherence/mod.rs
+++ b/compiler/rustc_typeck/src/coherence/mod.rs
@@ -57,7 +57,7 @@
             E0322,
             "explicit impls for the `Pointee` trait are not permitted"
         )
-        .span_label(span, "impl of 'Pointee' not allowed")
+        .span_label(span, "impl of `Pointee` not allowed")
         .emit();
         return;
     }
@@ -70,7 +70,7 @@
             E0322,
             "explicit impls for the `DiscriminantKind` trait are not permitted"
         )
-        .span_label(span, "impl of 'DiscriminantKind' not allowed")
+        .span_label(span, "impl of `DiscriminantKind` not allowed")
         .emit();
         return;
     }
@@ -83,7 +83,7 @@
             E0322,
             "explicit impls for the `Sized` trait are not permitted"
         )
-        .span_label(span, "impl of 'Sized' not allowed")
+        .span_label(span, "impl of `Sized` not allowed")
         .emit();
         return;
     }
diff --git a/compiler/rustc_typeck/src/coherence/orphan.rs b/compiler/rustc_typeck/src/coherence/orphan.rs
index f57986a..9ddfc8d 100644
--- a/compiler/rustc_typeck/src/coherence/orphan.rs
+++ b/compiler/rustc_typeck/src/coherence/orphan.rs
@@ -5,11 +5,13 @@
 use rustc_errors::struct_span_err;
 use rustc_errors::ErrorGuaranteed;
 use rustc_hir as hir;
-use rustc_index::bit_set::GrowableBitSet;
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_middle::ty::subst::GenericArgKind;
-use rustc_middle::ty::subst::{GenericArg, InternalSubsts};
-use rustc_middle::ty::{self, ImplPolarity, Ty, TyCtxt, TypeFoldable, TypeVisitor};
+use rustc_middle::ty::subst::InternalSubsts;
+use rustc_middle::ty::util::IgnoreRegions;
+use rustc_middle::ty::{
+    self, ImplPolarity, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable, TypeVisitor,
+};
 use rustc_session::lint;
 use rustc_span::def_id::{DefId, LocalDefId};
 use rustc_span::Span;
@@ -325,51 +327,6 @@
     })
 }
 
-#[derive(Default)]
-struct AreUniqueParamsVisitor {
-    seen: GrowableBitSet<u32>,
-}
-
-#[derive(Copy, Clone)]
-enum NotUniqueParam<'tcx> {
-    DuplicateParam(GenericArg<'tcx>),
-    NotParam(GenericArg<'tcx>),
-}
-
-impl<'tcx> TypeVisitor<'tcx> for AreUniqueParamsVisitor {
-    type BreakTy = NotUniqueParam<'tcx>;
-    fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
-        match t.kind() {
-            ty::Param(p) => {
-                if self.seen.insert(p.index) {
-                    ControlFlow::CONTINUE
-                } else {
-                    ControlFlow::Break(NotUniqueParam::DuplicateParam(t.into()))
-                }
-            }
-            _ => ControlFlow::Break(NotUniqueParam::NotParam(t.into())),
-        }
-    }
-    fn visit_region(&mut self, _: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
-        // We don't drop candidates during candidate assembly because of region
-        // constraints, so the behavior for impls only constrained by regions
-        // will not change.
-        ControlFlow::CONTINUE
-    }
-    fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
-        match c.val() {
-            ty::ConstKind::Param(p) => {
-                if self.seen.insert(p.index) {
-                    ControlFlow::CONTINUE
-                } else {
-                    ControlFlow::Break(NotUniqueParam::DuplicateParam(c.into()))
-                }
-            }
-            _ => ControlFlow::Break(NotUniqueParam::NotParam(c.into())),
-        }
-    }
-}
-
 /// Lint impls of auto traits if they are likely to have
 /// unsound or surprising effects on auto impls.
 fn lint_auto_trait_impls(tcx: TyCtxt<'_>, trait_def_id: DefId, impls: &[LocalDefId]) {
@@ -400,9 +357,9 @@
         // Impls which completely cover a given root type are fine as they
         // disable auto impls entirely. So only lint if the substs
         // are not a permutation of the identity substs.
-        match substs.visit_with(&mut AreUniqueParamsVisitor::default()) {
-            ControlFlow::Continue(()) => {} // ok
-            ControlFlow::Break(arg) => {
+        match tcx.uses_unique_generic_params(substs, IgnoreRegions::Yes) {
+            Ok(()) => {} // ok
+            Err(arg) => {
                 // Ideally:
                 //
                 // - compute the requirements for the auto impl candidate
@@ -429,13 +386,21 @@
             tcx.hir().local_def_id_to_hir_id(impl_def_id),
             tcx.def_span(impl_def_id),
             |err| {
+                let item_span = tcx.def_span(self_type_did);
+                let self_descr = tcx.def_kind(self_type_did).descr(self_type_did);
                 let mut err = err.build(&format!(
                     "cross-crate traits with a default impl, like `{}`, \
                          should not be specialized",
                     tcx.def_path_str(trait_def_id),
                 ));
-                let item_span = tcx.def_span(self_type_did);
-                let self_descr = tcx.def_kind(self_type_did).descr(self_type_did);
+                match arg {
+                    ty::util::NotUniqueParam::DuplicateParam(arg) => {
+                        err.note(&format!("`{}` is mentioned multiple times", arg));
+                    }
+                    ty::util::NotUniqueParam::NotParam(arg) => {
+                        err.note(&format!("`{}` is not a generic parameter", arg));
+                    }
+                }
                 err.span_note(
                     item_span,
                     &format!(
@@ -443,14 +408,6 @@
                         self_descr,
                     ),
                 );
-                match arg {
-                    NotUniqueParam::DuplicateParam(arg) => {
-                        err.note(&format!("`{}` is mentioned multiple times", arg));
-                    }
-                    NotUniqueParam::NotParam(arg) => {
-                        err.note(&format!("`{}` is not a generic parameter", arg));
-                    }
-                }
                 err.emit();
             },
         );
@@ -484,7 +441,7 @@
             }
 
             match t.kind() {
-                ty::Adt(def, substs) if def.is_phantom_data() => substs.super_visit_with(self),
+                ty::Adt(def, substs) if def.is_phantom_data() => substs.visit_with(self),
                 ty::Adt(def, substs) => {
                     // @lcnr: This is the only place where cycles can happen. We avoid this
                     // by only visiting each `DefId` once.
diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs
index cda817d..1f2e6ad 100644
--- a/compiler/rustc_typeck/src/collect.rs
+++ b/compiler/rustc_typeck/src/collect.rs
@@ -39,7 +39,7 @@
 use rustc_middle::ty::subst::InternalSubsts;
 use rustc_middle::ty::util::Discr;
 use rustc_middle::ty::util::IntTypeExt;
-use rustc_middle::ty::{self, AdtKind, Const, DefIdTree, Ty, TyCtxt};
+use rustc_middle::ty::{self, AdtKind, Const, DefIdTree, IsSuggestable, Ty, TyCtxt};
 use rustc_middle::ty::{ReprOptions, ToPredicate};
 use rustc_session::lint;
 use rustc_session::parse::feature_err;
@@ -59,10 +59,7 @@
 // Main entry point
 
 fn collect_mod_item_types(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
-    tcx.hir().visit_item_likes_in_module(
-        module_def_id,
-        &mut CollectItemTypesVisitor { tcx }.as_deep_visitor(),
-    );
+    tcx.hir().deep_visit_item_likes_in_module(module_def_id, &mut CollectItemTypesVisitor { tcx });
 }
 
 pub fn provide(providers: &mut Providers) {
@@ -113,7 +110,7 @@
 ///////////////////////////////////////////////////////////////////////////
 
 #[derive(Default)]
-crate struct HirPlaceholderCollector(crate Vec<Span>);
+pub(crate) struct HirPlaceholderCollector(pub(crate) Vec<Span>);
 
 impl<'v> Visitor<'v> for HirPlaceholderCollector {
     fn visit_ty(&mut self, t: &'v hir::Ty<'v>) {
@@ -147,7 +144,7 @@
 /// If there are any placeholder types (`_`), emit an error explaining that this is not allowed
 /// and suggest adding type parameters in the appropriate place, taking into consideration any and
 /// all already existing generic type parameters to avoid suggesting a name that is already in use.
-crate fn placeholder_type_error<'tcx>(
+pub(crate) fn placeholder_type_error<'tcx>(
     tcx: TyCtxt<'tcx>,
     generics: Option<&hir::Generics<'_>>,
     placeholder_types: Vec<Span>,
@@ -163,7 +160,7 @@
         .emit();
 }
 
-crate fn placeholder_type_error_diag<'tcx>(
+pub(crate) fn placeholder_type_error_diag<'tcx>(
     tcx: TyCtxt<'tcx>,
     generics: Option<&hir::Generics<'_>>,
     placeholder_types: Vec<Span>,
@@ -298,7 +295,7 @@
     }
 
     fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
-        if let hir::ExprKind::Closure(..) = expr.kind {
+        if let hir::ExprKind::Closure { .. } = expr.kind {
             let def_id = self.tcx.hir().local_def_id(expr.hir_id);
             self.tcx.ensure().generics_of(def_id);
             // We do not call `type_of` for closures here as that
@@ -452,8 +449,9 @@
                                     format!(
                                         "{}::",
                                         // Replace the existing lifetimes with a new named lifetime.
-                                        self.tcx
-                                            .replace_late_bound_regions(poly_trait_ref, |_| {
+                                        self.tcx.replace_late_bound_regions_uncached(
+                                            poly_trait_ref,
+                                            |_| {
                                                 self.tcx.mk_region(ty::ReEarlyBound(
                                                     ty::EarlyBoundRegion {
                                                         def_id: item_def_id,
@@ -461,8 +459,8 @@
                                                         name: Symbol::intern(&lt_name),
                                                     },
                                                 ))
-                                            })
-                                            .0,
+                                            }
+                                        ),
                                     ),
                                 ),
                             ];
@@ -808,8 +806,7 @@
                 hir::ItemKind::Fn(..) => tcx.ensure().fn_sig(def_id),
                 hir::ItemKind::OpaqueTy(..) => tcx.ensure().item_bounds(def_id),
                 hir::ItemKind::Const(ty, ..) | hir::ItemKind::Static(ty, ..) => {
-                    // (#75889): Account for `const C: dyn Fn() -> _ = "";`
-                    if let hir::TyKind::TraitObject(..) = ty.kind {
+                    if !is_suggestable_infer_ty(ty) {
                         let mut visitor = HirPlaceholderCollector::default();
                         visitor.visit_item(it);
                         placeholder_type_error(tcx, None, visitor.0, false, None, it.kind.descr());
@@ -1367,7 +1364,6 @@
 
     fn has_late_bound_regions<'tcx>(
         tcx: TyCtxt<'tcx>,
-        def_id: LocalDefId,
         generics: &'tcx hir::Generics<'tcx>,
         decl: &'tcx hir::FnDecl<'tcx>,
     ) -> Option<Span> {
@@ -1376,14 +1372,9 @@
             outer_index: ty::INNERMOST,
             has_late_bound_regions: None,
         };
-        let late_bound_map = tcx.is_late_bound_map(def_id);
-        let is_late_bound = |id| {
-            let id = tcx.hir().local_def_id(id);
-            late_bound_map.map_or(false, |(_, set)| set.contains(&id))
-        };
         for param in generics.params {
             if let GenericParamKind::Lifetime { .. } = param.kind {
-                if is_late_bound(param.hir_id) {
+                if tcx.is_late_bound(param.hir_id) {
                     return Some(param.span);
                 }
             }
@@ -1395,25 +1386,25 @@
     match node {
         Node::TraitItem(item) => match item.kind {
             hir::TraitItemKind::Fn(ref sig, _) => {
-                has_late_bound_regions(tcx, item.def_id, &item.generics, sig.decl)
+                has_late_bound_regions(tcx, &item.generics, sig.decl)
             }
             _ => None,
         },
         Node::ImplItem(item) => match item.kind {
             hir::ImplItemKind::Fn(ref sig, _) => {
-                has_late_bound_regions(tcx, item.def_id, &item.generics, sig.decl)
+                has_late_bound_regions(tcx, &item.generics, sig.decl)
             }
             _ => None,
         },
         Node::ForeignItem(item) => match item.kind {
             hir::ForeignItemKind::Fn(fn_decl, _, ref generics) => {
-                has_late_bound_regions(tcx, item.def_id, generics, fn_decl)
+                has_late_bound_regions(tcx, generics, fn_decl)
             }
             _ => None,
         },
         Node::Item(item) => match item.kind {
             hir::ItemKind::Fn(ref sig, .., ref generics, _) => {
-                has_late_bound_regions(tcx, item.def_id, generics, sig.decl)
+                has_late_bound_regions(tcx, generics, sig.decl)
             }
             _ => None,
         },
@@ -1559,11 +1550,23 @@
                     Node::Expr(&Expr { kind: ExprKind::ConstBlock(_), .. }) => {
                         Some(tcx.typeck_root_def_id(def_id))
                     }
+                    // Exclude `GlobalAsm` here which cannot have generics.
+                    Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. })
+                        if asm.operands.iter().any(|(op, _op_sp)| match op {
+                            hir::InlineAsmOperand::Const { anon_const }
+                            | hir::InlineAsmOperand::SymFn { anon_const } => {
+                                anon_const.hir_id == hir_id
+                            }
+                            _ => false,
+                        }) =>
+                    {
+                        Some(parent_def_id.to_def_id())
+                    }
                     _ => None,
                 }
             }
         }
-        Node::Expr(&hir::Expr { kind: hir::ExprKind::Closure(..), .. }) => {
+        Node::Expr(&hir::Expr { kind: hir::ExprKind::Closure { .. }, .. }) => {
             Some(tcx.typeck_root_def_id(def_id))
         }
         Node::Item(item) => match item.kind {
@@ -1585,41 +1588,20 @@
         _ => None,
     };
 
-    let mut opt_self = None;
-    let mut allow_defaults = false;
-
     let no_generics = hir::Generics::empty();
-    let ast_generics = match node {
-        Node::TraitItem(item) => &item.generics,
-
-        Node::ImplItem(item) => &item.generics,
-
+    let ast_generics = node.generics().unwrap_or(&no_generics);
+    let (opt_self, allow_defaults) = match node {
         Node::Item(item) => {
             match item.kind {
-                ItemKind::Fn(.., ref generics, _)
-                | ItemKind::Impl(hir::Impl { ref generics, .. }) => generics,
-
-                ItemKind::TyAlias(_, ref generics)
-                | ItemKind::Enum(_, ref generics)
-                | ItemKind::Struct(_, ref generics)
-                | ItemKind::OpaqueTy(hir::OpaqueTy { ref generics, .. })
-                | ItemKind::Union(_, ref generics) => {
-                    allow_defaults = true;
-                    generics
-                }
-
-                ItemKind::Trait(_, _, ref generics, ..)
-                | ItemKind::TraitAlias(ref generics, ..) => {
+                ItemKind::Trait(..) | ItemKind::TraitAlias(..) => {
                     // Add in the self type parameter.
                     //
                     // Something of a hack: use the node id for the trait, also as
                     // the node id for the Self type parameter.
-                    let param_id = item.def_id;
-
-                    opt_self = Some(ty::GenericParamDef {
+                    let opt_self = Some(ty::GenericParamDef {
                         index: 0,
                         name: kw::SelfUpper,
-                        def_id: param_id.to_def_id(),
+                        def_id,
                         pure_wrt_drop: false,
                         kind: ty::GenericParamDefKind::Type {
                             has_default: false,
@@ -1628,21 +1610,17 @@
                         },
                     });
 
-                    allow_defaults = true;
-                    generics
+                    (opt_self, true)
                 }
-
-                _ => &no_generics,
+                ItemKind::TyAlias(..)
+                | ItemKind::Enum(..)
+                | ItemKind::Struct(..)
+                | ItemKind::OpaqueTy(..)
+                | ItemKind::Union(..) => (None, true),
+                _ => (None, false),
             }
         }
-
-        Node::ForeignItem(item) => match item.kind {
-            ForeignItemKind::Static(..) => &no_generics,
-            ForeignItemKind::Fn(_, _, ref generics) => generics,
-            ForeignItemKind::Type => &no_generics,
-        },
-
-        _ => &no_generics,
+        _ => (None, false),
     };
 
     let has_self = opt_self.is_some();
@@ -1662,7 +1640,7 @@
         params.push(opt_self);
     }
 
-    let early_lifetimes = early_bound_lifetimes_from_generics(tcx, hir_id.owner, ast_generics);
+    let early_lifetimes = early_bound_lifetimes_from_generics(tcx, ast_generics);
     params.extend(early_lifetimes.enumerate().map(|(i, param)| ty::GenericParamDef {
         name: param.name.ident().name,
         index: own_start + i as u32,
@@ -1739,7 +1717,9 @@
     // provide junk type parameter defs - the only place that
     // cares about anything but the length is instantiation,
     // and we don't do that for closures.
-    if let Node::Expr(&hir::Expr { kind: hir::ExprKind::Closure(.., gen), .. }) = node {
+    if let Node::Expr(&hir::Expr { kind: hir::ExprKind::Closure { movability: gen, .. }, .. }) =
+        node
+    {
         let dummy_args = if gen.is_some() {
             &["<resume_ty>", "<yield_ty>", "<return_ty>", "<witness>", "<upvars>"][..]
         } else {
@@ -1902,7 +1882,7 @@
             ))
         }
 
-        Expr(&hir::Expr { kind: hir::ExprKind::Closure(..), .. }) => {
+        Expr(&hir::Expr { kind: hir::ExprKind::Closure { .. }, .. }) => {
             // Closure signatures are not like other function
             // signatures and cannot be accessed through `fn_sig`. For
             // example, a closure signature excludes the `self`
@@ -1951,7 +1931,7 @@
                 diag.span_suggestion(
                     ty.span,
                     "replace with the correct return type",
-                    ret_ty.to_string(),
+                    ret_ty,
                     Applicability::MachineApplicable,
                 );
             } else if matches!(ret_ty.kind(), ty::FnDef(..)) {
@@ -1960,7 +1940,7 @@
                     diag.span_suggestion(
                         ty.span,
                         "replace with the correct return type",
-                        fn_sig.to_string(),
+                        fn_sig,
                         Applicability::MachineApplicable,
                     );
                 }
@@ -2045,23 +2025,10 @@
 /// `resolve_lifetime::early_bound_lifetimes`.
 fn early_bound_lifetimes_from_generics<'a, 'tcx: 'a>(
     tcx: TyCtxt<'tcx>,
-    def_id: LocalDefId,
     generics: &'a hir::Generics<'a>,
 ) -> impl Iterator<Item = &'a hir::GenericParam<'a>> + Captures<'tcx> {
-    let late_bound_map = if generics.params.is_empty() {
-        // This function may be called on `def_id == CRATE_DEF_ID`,
-        // which makes `is_late_bound_map` ICE.  Don't even try if there
-        // is no generic parameter.
-        None
-    } else {
-        tcx.is_late_bound_map(def_id)
-    };
-    let is_late_bound = move |hir_id| {
-        let id = tcx.hir().local_def_id(hir_id);
-        late_bound_map.map_or(false, |(_, set)| set.contains(&id))
-    };
     generics.params.iter().filter(move |param| match param.kind {
-        GenericParamKind::Lifetime { .. } => !is_late_bound(param.hir_id),
+        GenericParamKind::Lifetime { .. } => !tcx.is_late_bound(param.hir_id),
         _ => false,
     })
 }
@@ -2246,7 +2213,7 @@
     // have to be careful to only iterate over early-bound regions.
     let mut index = parent_count
         + has_own_self as u32
-        + early_bound_lifetimes_from_generics(tcx, hir_id.owner, ast_generics).count() as u32;
+        + early_bound_lifetimes_from_generics(tcx, ast_generics).count() as u32;
 
     // Collect the predicates that were written inline by the user on each
     // type parameter (e.g., `<T: Foo>`).
@@ -2387,7 +2354,7 @@
         fn visit_anon_const(&mut self, c: &'tcx hir::AnonConst) {
             let def_id = self.tcx.hir().local_def_id(c.hir_id);
             let ct = ty::Const::from_anon_const(self.tcx, def_id);
-            if let ty::ConstKind::Unevaluated(uv) = ct.val() {
+            if let ty::ConstKind::Unevaluated(uv) = ct.kind() {
                 assert_eq!(uv.promoted, None);
                 let span = self.tcx.hir().span(c.hir_id);
                 self.preds.insert((
@@ -2445,7 +2412,7 @@
     gather_explicit_predicates_of(tcx, def_id.to_def_id())
 }
 
-fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicates<'_> {
+fn explicit_predicates_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> ty::GenericPredicates<'tcx> {
     let def_kind = tcx.def_kind(def_id);
     if let DefKind::Trait = def_kind {
         // Remove bounds on associated types from the predicates, they will be
@@ -2453,7 +2420,7 @@
         let predicates_and_bounds = tcx.trait_explicit_predicates_and_bounds(def_id.expect_local());
         let trait_identity_substs = InternalSubsts::identity_for_item(tcx, def_id);
 
-        let is_assoc_item_ty = |ty: Ty<'_>| {
+        let is_assoc_item_ty = |ty: Ty<'tcx>| {
             // For a predicate from a where clause to become a bound on an
             // associated type:
             // * It must use the identity substs of the item.
@@ -2601,9 +2568,9 @@
 fn generator_kind(tcx: TyCtxt<'_>, def_id: DefId) -> Option<hir::GeneratorKind> {
     match tcx.hir().get_if_local(def_id) {
         Some(Node::Expr(&rustc_hir::Expr {
-            kind: rustc_hir::ExprKind::Closure(_, _, body_id, _, _),
+            kind: rustc_hir::ExprKind::Closure { body, .. },
             ..
-        })) => tcx.hir().body(body_id).generator_kind(),
+        })) => tcx.hir().body(body).generator_kind(),
         Some(_) => None,
         _ => bug!("generator_kind applied to non-local def-id {:?}", def_id),
     }
@@ -2618,7 +2585,7 @@
     let Some(list) = attr.meta_item_list() else { return };
     let bad_item = |span| {
         let msg = "malformed `target_feature` attribute input";
-        let code = "enable = \"..\"".to_owned();
+        let code = "enable = \"..\"";
         tcx.sess
             .struct_span_err(span, msg)
             .span_suggestion(span, "must be of the form", code, Applicability::HasPlaceholders)
diff --git a/compiler/rustc_typeck/src/collect/type_of.rs b/compiler/rustc_typeck/src/collect/type_of.rs
index 4b6f80c..7011dd6 100644
--- a/compiler/rustc_typeck/src/collect/type_of.rs
+++ b/compiler/rustc_typeck/src/collect/type_of.rs
@@ -8,7 +8,7 @@
 use rustc_middle::hir::nested_filter;
 use rustc_middle::ty::subst::InternalSubsts;
 use rustc_middle::ty::util::IntTypeExt;
-use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt, TypeFoldable, TypeFolder};
+use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable};
 use rustc_span::symbol::Ident;
 use rustc_span::{Span, DUMMY_SP};
 
@@ -161,38 +161,23 @@
             // We've encountered an `AnonConst` in some path, so we need to
             // figure out which generic parameter it corresponds to and return
             // the relevant type.
-            let filtered = path.segments.iter().find_map(|seg| {
-                seg.args?
-                    .args
+            let Some((arg_index, segment)) = path.segments.iter().find_map(|seg| {
+                let args = seg.args?;
+                args.args
+                .iter()
+                .filter(|arg| arg.is_ty_or_const())
+                .position(|arg| arg.id() == hir_id)
+                .map(|index| (index, seg)).or_else(|| args.bindings
                     .iter()
-                    .filter(|arg| arg.is_ty_or_const())
-                    .position(|arg| arg.id() == hir_id)
-                    .map(|index| (index, seg))
-            });
-
-            // FIXME(associated_const_generics): can we blend this with iteration above?
-            let (arg_index, segment) = match filtered {
-                None => {
-                    let binding_filtered = path.segments.iter().find_map(|seg| {
-                        seg.args?
-                            .bindings
-                            .iter()
-                            .filter_map(TypeBinding::opt_const)
-                            .position(|ct| ct.hir_id == hir_id)
-                            .map(|idx| (idx, seg))
-                    });
-                    match binding_filtered {
-                        Some(inner) => inner,
-                        None => {
-                            tcx.sess.delay_span_bug(
-                                tcx.def_span(def_id),
-                                "no arg matching AnonConst in path",
-                            );
-                            return None;
-                        }
-                    }
-                }
-                Some(inner) => inner,
+                    .filter_map(TypeBinding::opt_const)
+                    .position(|ct| ct.hir_id == hir_id)
+                    .map(|idx| (idx, seg)))
+            }) else {
+                tcx.sess.delay_span_bug(
+                    tcx.def_span(def_id),
+                    "no arg matching AnonConst in path",
+                );
+                return None;
             };
 
             // Try to use the segment resolution if it is valid, otherwise we
@@ -420,7 +405,7 @@
 
         Node::Field(field) => icx.to_ty(field.ty),
 
-        Node::Expr(&Expr { kind: ExprKind::Closure(..), .. }) => tcx.typeck(def_id).node_type(hir_id),
+        Node::Expr(&Expr { kind: ExprKind::Closure{..}, .. }) => tcx.typeck(def_id).node_type(hir_id),
 
         Node::AnonConst(_) if let Some(param) = tcx.opt_const_param_of(def_id) => {
             // We defer to `type_of` of the corresponding parameter
@@ -465,21 +450,10 @@
                     .discr_type()
                     .to_ty(tcx),
 
-                Node::TraitRef(trait_ref @ &TraitRef {
-                  path, ..
-                }) if let Some((binding, seg)) =
-                  path
-                      .segments
-                      .iter()
-                      .find_map(|seg| {
-                          seg.args?.bindings
-                              .iter()
-                              .find_map(|binding| if binding.opt_const()?.hir_id == hir_id {
-                                Some((binding, seg))
-                              } else {
-                                None
-                              })
-                      }) =>
+                Node::TypeBinding(binding @ &TypeBinding { hir_id: binding_id, ..  })
+                    if let Node::TraitRef(trait_ref) = tcx.hir().get(
+                        tcx.hir().get_parent_node(binding_id)
+                    ) =>
                 {
                   let Some(trait_def_id) = trait_ref.trait_def_id() else {
                     return tcx.ty_error_with_message(DUMMY_SP, "Could not find trait");
@@ -619,7 +593,7 @@
             self.tcx.hir()
         }
         fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) {
-            if let hir::ExprKind::Closure(..) = ex.kind {
+            if let hir::ExprKind::Closure { .. } = ex.kind {
                 let def_id = self.tcx.hir().local_def_id(ex.hir_id);
                 self.check(def_id);
             }
@@ -782,7 +756,7 @@
                     diag.span_suggestion(
                         span,
                         "replace with the correct type",
-                        sugg_ty.to_string(),
+                        sugg_ty,
                         Applicability::MaybeIncorrect,
                     );
                 } else {
diff --git a/compiler/rustc_typeck/src/constrained_generic_params.rs b/compiler/rustc_typeck/src/constrained_generic_params.rs
index 7f2e57e..858cf63 100644
--- a/compiler/rustc_typeck/src/constrained_generic_params.rs
+++ b/compiler/rustc_typeck/src/constrained_generic_params.rs
@@ -1,5 +1,5 @@
 use rustc_data_structures::fx::FxHashSet;
-use rustc_middle::ty::fold::{TypeFoldable, TypeVisitor};
+use rustc_middle::ty::fold::{TypeFoldable, TypeSuperFoldable, TypeVisitor};
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_span::source_map::Span;
 use std::ops::ControlFlow;
@@ -80,7 +80,7 @@
     }
 
     fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
-        match c.val() {
+        match c.kind() {
             ty::ConstKind::Unevaluated(..) if !self.include_nonconstraining => {
                 // Constant expressions are not injective
                 return c.ty().visit_with(self);
diff --git a/compiler/rustc_typeck/src/errors.rs b/compiler/rustc_typeck/src/errors.rs
index cd3813c..67a3d4a 100644
--- a/compiler/rustc_typeck/src/errors.rs
+++ b/compiler/rustc_typeck/src/errors.rs
@@ -1,7 +1,5 @@
 //! Errors emitted by typeck.
-use rustc_errors::{
-    error_code, Applicability, DiagnosticBuilder, DiagnosticMessage, ErrorGuaranteed,
-};
+use rustc_errors::{error_code, Applicability, DiagnosticBuilder, ErrorGuaranteed};
 use rustc_macros::{SessionDiagnostic, SessionSubdiagnostic};
 use rustc_middle::ty::Ty;
 use rustc_session::{parse::ParseSess, SessionDiagnostic};
@@ -243,17 +241,6 @@
     pub name: Symbol,
 }
 
-#[derive(SessionDiagnostic)]
-#[error(code = "E0632", slug = "typeck-explicit-generic-args-with-impl-trait")]
-#[note]
-pub struct ExplicitGenericArgsWithImplTrait {
-    #[primary_span]
-    #[label]
-    pub spans: Vec<Span>,
-    #[help]
-    pub is_nightly_build: Option<()>,
-}
-
 pub struct MissingTypeParams {
     pub span: Span,
     pub def_span: Span,
@@ -264,10 +251,9 @@
 // Manual implementation of `SessionDiagnostic` to be able to call `span_to_snippet`.
 impl<'a> SessionDiagnostic<'a> for MissingTypeParams {
     fn into_diagnostic(self, sess: &'a ParseSess) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
-        static SLUG: &'static str = "typeck-missing-type-params";
         let mut err = sess.span_diagnostic.struct_span_err_with_code(
             self.span,
-            DiagnosticMessage::fluent(SLUG),
+            rustc_errors::fluent::typeck::missing_type_params,
             error_code!(E0393),
         );
         err.set_arg("parameterCount", self.missing_type_params.len());
@@ -280,7 +266,7 @@
                 .join(", "),
         );
 
-        err.span_label(self.def_span, DiagnosticMessage::fluent_attr(SLUG, "label"));
+        err.span_label(self.def_span, rustc_errors::fluent::typeck::label);
 
         let mut suggested = false;
         if let (Ok(snippet), true) = (
@@ -298,7 +284,7 @@
                 // least we can clue them to the correct syntax `Iterator<Type>`.
                 err.span_suggestion(
                     self.span,
-                    DiagnosticMessage::fluent_attr(SLUG, "suggestion"),
+                    rustc_errors::fluent::typeck::suggestion,
                     format!("{}<{}>", snippet, self.missing_type_params.join(", ")),
                     Applicability::HasPlaceholders,
                 );
@@ -306,10 +292,10 @@
             }
         }
         if !suggested {
-            err.span_label(self.span, DiagnosticMessage::fluent_attr(SLUG, "no-suggestion-label"));
+            err.span_label(self.span, rustc_errors::fluent::typeck::no_suggestion_label);
         }
 
-        err.note(DiagnosticMessage::fluent_attr(SLUG, "note"));
+        err.note(rustc_errors::fluent::typeck::note);
         err
     }
 }
diff --git a/compiler/rustc_typeck/src/expr_use_visitor.rs b/compiler/rustc_typeck/src/expr_use_visitor.rs
index e69ba99..920e3d5 100644
--- a/compiler/rustc_typeck/src/expr_use_visitor.rs
+++ b/compiler/rustc_typeck/src/expr_use_visitor.rs
@@ -17,6 +17,7 @@
 use rustc_middle::mir::FakeReadCause;
 use rustc_middle::ty::{self, adjustment, AdtKind, Ty, TyCtxt};
 use rustc_target::abi::VariantIdx;
+use ty::BorrowKind::ImmBorrow;
 
 use crate::mem_categorization as mc;
 
@@ -69,7 +70,12 @@
     }
 
     /// The `place` should be a fake read because of specified `cause`.
-    fn fake_read(&mut self, place: Place<'tcx>, cause: FakeReadCause, diag_expr_id: hir::HirId);
+    fn fake_read(
+        &mut self,
+        place_with_id: &PlaceWithHirId<'tcx>,
+        cause: FakeReadCause,
+        diag_expr_id: hir::HirId,
+    );
 }
 
 #[derive(Copy, Clone, PartialEq, Debug)]
@@ -327,7 +333,7 @@
                     };
 
                     self.delegate.fake_read(
-                        discr_place.place.clone(),
+                        &discr_place,
                         FakeReadCause::ForMatchedPlace(closure_def_id),
                         discr_place.hir_id,
                     );
@@ -431,7 +437,7 @@
                 self.consume_expr(base);
             }
 
-            hir::ExprKind::Closure(..) => {
+            hir::ExprKind::Closure { .. } => {
                 self.walk_captures(expr);
             }
 
@@ -617,16 +623,16 @@
         };
 
         self.delegate.fake_read(
-            discr_place.place.clone(),
+            discr_place,
             FakeReadCause::ForMatchedPlace(closure_def_id),
             discr_place.hir_id,
         );
-        self.walk_pat(discr_place, arm.pat);
+        self.walk_pat(discr_place, arm.pat, arm.guard.is_some());
 
         if let Some(hir::Guard::If(e)) = arm.guard {
             self.consume_expr(e)
-        } else if let Some(hir::Guard::IfLet(_, ref e)) = arm.guard {
-            self.consume_expr(e)
+        } else if let Some(hir::Guard::IfLet(ref l)) = arm.guard {
+            self.consume_expr(l.init)
         }
 
         self.consume_expr(arm.body);
@@ -641,16 +647,21 @@
         };
 
         self.delegate.fake_read(
-            discr_place.place.clone(),
+            discr_place,
             FakeReadCause::ForLet(closure_def_id),
             discr_place.hir_id,
         );
-        self.walk_pat(discr_place, pat);
+        self.walk_pat(discr_place, pat, false);
     }
 
     /// The core driver for walking a pattern
-    fn walk_pat(&mut self, discr_place: &PlaceWithHirId<'tcx>, pat: &hir::Pat<'_>) {
-        debug!("walk_pat(discr_place={:?}, pat={:?})", discr_place, pat);
+    fn walk_pat(
+        &mut self,
+        discr_place: &PlaceWithHirId<'tcx>,
+        pat: &hir::Pat<'_>,
+        has_guard: bool,
+    ) {
+        debug!("walk_pat(discr_place={:?}, pat={:?}, has_guard={:?})", discr_place, pat, has_guard);
 
         let tcx = self.tcx();
         let ExprUseVisitor { ref mc, body_owner: _, ref mut delegate } = *self;
@@ -671,6 +682,13 @@
                         delegate.bind(binding_place, binding_place.hir_id);
                     }
 
+                    // Subtle: MIR desugaring introduces immutable borrows for each pattern
+                    // binding when lowering pattern guards to ensure that the guard does not
+                    // modify the scrutinee.
+                    if has_guard {
+                        delegate.borrow(place, discr_place.hir_id, ImmBorrow);
+                    }
+
                     // It is also a borrow or copy/move of the value being matched.
                     // In a cases of pattern like `let pat = upvar`, don't use the span
                     // of the pattern, as this just looks confusing, instead use the span
@@ -764,7 +782,11 @@
                         );
                     }
                 };
-                self.delegate.fake_read(fake_read.clone(), *cause, *hir_id);
+                self.delegate.fake_read(
+                    &PlaceWithHirId { place: fake_read.clone(), hir_id: *hir_id },
+                    *cause,
+                    *hir_id,
+                );
             }
         }
 
diff --git a/compiler/rustc_typeck/src/hir_wf_check.rs b/compiler/rustc_typeck/src/hir_wf_check.rs
index b4b438a..4392b9a 100644
--- a/compiler/rustc_typeck/src/hir_wf_check.rs
+++ b/compiler/rustc_typeck/src/hir_wf_check.rs
@@ -1,7 +1,7 @@
 use crate::collect::ItemCtxt;
 use rustc_hir as hir;
 use rustc_hir::intravisit::{self, Visitor};
-use rustc_hir::HirId;
+use rustc_hir::{ForeignItem, ForeignItemKind, HirId};
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_infer::traits::TraitEngine;
 use rustc_infer::traits::{ObligationCause, WellFormedLoc};
@@ -141,6 +141,9 @@
                 ref item => bug!("Unexpected item {:?}", item),
             },
             hir::Node::Field(field) => Some(field.ty),
+            hir::Node::ForeignItem(ForeignItem {
+                kind: ForeignItemKind::Static(ty, _), ..
+            }) => Some(*ty),
             ref node => bug!("Unexpected node {:?}", node),
         },
         WellFormedLoc::Param { function: _, param_idx } => {
diff --git a/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs b/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs
index bb97d00..0ecc28e 100644
--- a/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs
+++ b/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs
@@ -71,7 +71,7 @@
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_infer::infer::outlives::env::OutlivesEnvironment;
-use rustc_infer::infer::{InferCtxt, RegionckMode, TyCtxtInferExt};
+use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
 use rustc_infer::traits::specialization_graph::Node;
 use rustc_middle::ty::subst::{GenericArg, InternalSubsts, SubstsRef};
 use rustc_middle::ty::trait_def::TraitSpecializationKind;
@@ -164,7 +164,7 @@
 
     // Conservatively use an empty `ParamEnv`.
     let outlives_env = OutlivesEnvironment::new(ty::ParamEnv::empty());
-    infcx.resolve_regions_and_report_errors(impl1_def_id, &outlives_env, RegionckMode::default());
+    infcx.resolve_regions_and_report_errors(impl1_def_id, &outlives_env);
     let Ok(impl2_substs) = infcx.fully_resolve(impl2_substs) else {
         tcx.sess.emit_err(SubstsOnOverriddenImpl { span });
         return None;
diff --git a/compiler/rustc_typeck/src/lib.rs b/compiler/rustc_typeck/src/lib.rs
index 67c6e79..d613edf 100644
--- a/compiler/rustc_typeck/src/lib.rs
+++ b/compiler/rustc_typeck/src/lib.rs
@@ -59,17 +59,16 @@
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![feature(box_patterns)]
 #![feature(control_flow_enum)]
-#![feature(crate_visibility_modifier)]
 #![feature(drain_filter)]
 #![feature(hash_drain_filter)]
 #![feature(if_let_guard)]
 #![feature(is_sorted)]
+#![feature(iter_intersperse)]
 #![feature(label_break_value)]
 #![feature(let_chains)]
 #![feature(let_else)]
 #![feature(min_specialization)]
 #![feature(never_type)]
-#![feature(nll)]
 #![feature(once_cell)]
 #![feature(slice_partition_dedup)]
 #![feature(try_blocks)]
@@ -212,7 +211,7 @@
         let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
         match tcx.hir().find(hir_id) {
             Some(Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, ref generics, _), .. })) => {
-                generics.where_clause_span()
+                Some(generics.where_clause_span)
             }
             _ => {
                 span_bug!(tcx.def_span(def_id), "main has a non-function type");
@@ -402,14 +401,17 @@
                         .emit();
                         error = true;
                     }
-                    if let Some(sp) = generics.where_clause_span() {
+                    if generics.has_where_clause_predicates {
                         struct_span_err!(
                             tcx.sess,
-                            sp,
+                            generics.where_clause_span,
                             E0647,
                             "start function is not allowed to have a `where` clause"
                         )
-                        .span_label(sp, "start function cannot have a `where` clause")
+                        .span_label(
+                            generics.where_clause_span,
+                            "start function cannot have a `where` clause",
+                        )
                         .emit();
                         error = true;
                     }
diff --git a/compiler/rustc_typeck/src/mem_categorization.rs b/compiler/rustc_typeck/src/mem_categorization.rs
index 3d7b659..9acae8d 100644
--- a/compiler/rustc_typeck/src/mem_categorization.rs
+++ b/compiler/rustc_typeck/src/mem_categorization.rs
@@ -65,7 +65,7 @@
 use rustc_target::abi::VariantIdx;
 use rustc_trait_selection::infer::InferCtxtExt;
 
-crate trait HirNode {
+pub(crate) trait HirNode {
     fn hir_id(&self) -> hir::HirId;
     fn span(&self) -> Span;
 }
@@ -89,19 +89,19 @@
 }
 
 #[derive(Clone)]
-crate struct MemCategorizationContext<'a, 'tcx> {
-    crate typeck_results: &'a ty::TypeckResults<'tcx>,
+pub(crate) struct MemCategorizationContext<'a, 'tcx> {
+    pub(crate) typeck_results: &'a ty::TypeckResults<'tcx>,
     infcx: &'a InferCtxt<'a, 'tcx>,
     param_env: ty::ParamEnv<'tcx>,
     body_owner: LocalDefId,
     upvars: Option<&'tcx FxIndexMap<hir::HirId, hir::Upvar>>,
 }
 
-crate type McResult<T> = Result<T, ()>;
+pub(crate) type McResult<T> = Result<T, ()>;
 
 impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
     /// Creates a `MemCategorizationContext`.
-    crate fn new(
+    pub(crate) fn new(
         infcx: &'a InferCtxt<'a, 'tcx>,
         param_env: ty::ParamEnv<'tcx>,
         body_owner: LocalDefId,
@@ -116,11 +116,11 @@
         }
     }
 
-    crate fn tcx(&self) -> TyCtxt<'tcx> {
+    pub(crate) fn tcx(&self) -> TyCtxt<'tcx> {
         self.infcx.tcx
     }
 
-    crate fn type_is_copy_modulo_regions(&self, ty: Ty<'tcx>, span: Span) -> bool {
+    pub(crate) fn type_is_copy_modulo_regions(&self, ty: Ty<'tcx>, span: Span) -> bool {
         self.infcx.type_is_copy_modulo_regions(self.param_env, ty, span)
     }
 
@@ -162,7 +162,7 @@
         }
     }
 
-    crate fn node_ty(&self, hir_id: hir::HirId) -> McResult<Ty<'tcx>> {
+    pub(crate) fn node_ty(&self, hir_id: hir::HirId) -> McResult<Ty<'tcx>> {
         self.resolve_type_vars_or_error(hir_id, self.typeck_results.node_type_opt(hir_id))
     }
 
@@ -170,7 +170,7 @@
         self.resolve_type_vars_or_error(expr.hir_id, self.typeck_results.expr_ty_opt(expr))
     }
 
-    crate fn expr_ty_adjusted(&self, expr: &hir::Expr<'_>) -> McResult<Ty<'tcx>> {
+    pub(crate) fn expr_ty_adjusted(&self, expr: &hir::Expr<'_>) -> McResult<Ty<'tcx>> {
         self.resolve_type_vars_or_error(expr.hir_id, self.typeck_results.expr_ty_adjusted_opt(expr))
     }
 
@@ -184,7 +184,7 @@
     ///   implicit deref patterns attached (e.g., it is really
     ///   `&Some(x)`). In that case, we return the "outermost" type
     ///   (e.g., `&Option<T>).
-    crate fn pat_ty_adjusted(&self, pat: &hir::Pat<'_>) -> McResult<Ty<'tcx>> {
+    pub(crate) fn pat_ty_adjusted(&self, pat: &hir::Pat<'_>) -> McResult<Ty<'tcx>> {
         // Check for implicit `&` types wrapping the pattern; note
         // that these are never attached to binding patterns, so
         // actually this is somewhat "disjoint" from the code below
@@ -236,7 +236,7 @@
         Ok(ret_ty)
     }
 
-    crate fn cat_expr(&self, expr: &hir::Expr<'_>) -> McResult<PlaceWithHirId<'tcx>> {
+    pub(crate) fn cat_expr(&self, expr: &hir::Expr<'_>) -> McResult<PlaceWithHirId<'tcx>> {
         // This recursion helper avoids going through *too many*
         // adjustments, since *only* non-overloaded deref recurses.
         fn helper<'a, 'tcx>(
@@ -255,7 +255,7 @@
         helper(self, expr, self.typeck_results.expr_adjustments(expr))
     }
 
-    crate fn cat_expr_adjusted(
+    pub(crate) fn cat_expr_adjusted(
         &self,
         expr: &hir::Expr<'_>,
         previous: PlaceWithHirId<'tcx>,
@@ -298,7 +298,10 @@
         }
     }
 
-    crate fn cat_expr_unadjusted(&self, expr: &hir::Expr<'_>) -> McResult<PlaceWithHirId<'tcx>> {
+    pub(crate) fn cat_expr_unadjusted(
+        &self,
+        expr: &hir::Expr<'_>,
+    ) -> McResult<PlaceWithHirId<'tcx>> {
         debug!("cat_expr: id={} expr={:?}", expr.hir_id, expr);
 
         let expr_ty = self.expr_ty(expr)?;
@@ -356,7 +359,7 @@
             | hir::ExprKind::Call(..)
             | hir::ExprKind::Assign(..)
             | hir::ExprKind::AssignOp(..)
-            | hir::ExprKind::Closure(..)
+            | hir::ExprKind::Closure { .. }
             | hir::ExprKind::Ret(..)
             | hir::ExprKind::Unary(..)
             | hir::ExprKind::Yield(..)
@@ -383,7 +386,7 @@
         }
     }
 
-    crate fn cat_res(
+    pub(crate) fn cat_res(
         &self,
         hir_id: hir::HirId,
         span: Span,
@@ -440,7 +443,7 @@
         Ok(ret)
     }
 
-    crate fn cat_rvalue(
+    pub(crate) fn cat_rvalue(
         &self,
         hir_id: hir::HirId,
         span: Span,
@@ -452,7 +455,7 @@
         ret
     }
 
-    crate fn cat_projection<N: HirNode>(
+    pub(crate) fn cat_projection<N: HirNode>(
         &self,
         node: &N,
         base_place: PlaceWithHirId<'tcx>,
@@ -521,7 +524,7 @@
         Ok(ret)
     }
 
-    crate fn cat_pattern<F>(
+    pub(crate) fn cat_pattern<F>(
         &self,
         place: PlaceWithHirId<'tcx>,
         pat: &hir::Pat<'_>,
diff --git a/compiler/rustc_typeck/src/outlives/mod.rs b/compiler/rustc_typeck/src/outlives/mod.rs
index 139be8a..dccfee1 100644
--- a/compiler/rustc_typeck/src/outlives/mod.rs
+++ b/compiler/rustc_typeck/src/outlives/mod.rs
@@ -9,7 +9,7 @@
 
 mod explicit;
 mod implicit_infer;
-crate mod outlives_bounds;
+pub(crate) mod outlives_bounds;
 /// Code to write unit test for outlives.
 pub mod test;
 mod utils;
diff --git a/compiler/rustc_typeck/src/outlives/outlives_bounds.rs b/compiler/rustc_typeck/src/outlives/outlives_bounds.rs
index 87f844f..3bf697e 100644
--- a/compiler/rustc_typeck/src/outlives/outlives_bounds.rs
+++ b/compiler/rustc_typeck/src/outlives/outlives_bounds.rs
@@ -1,9 +1,8 @@
 use rustc_hir as hir;
-use rustc_infer::traits::TraitEngineExt as _;
 use rustc_middle::ty::{self, Ty};
 use rustc_span::source_map::Span;
-use rustc_trait_selection::infer::canonical::OriginalQueryValues;
 use rustc_trait_selection::infer::InferCtxt;
+use rustc_trait_selection::traits::query::type_op::{self, TypeOp, TypeOpOutput};
 use rustc_trait_selection::traits::query::NoSolution;
 use rustc_trait_selection::traits::{FulfillmentContext, ObligationCause, TraitEngine};
 
@@ -41,6 +40,7 @@
     /// - `ty`, the type that we are supposed to assume is WF.
     /// - `span`, a span to use when normalizing, hopefully not important,
     ///   might be useful if a `bug!` occurs.
+    #[instrument(level = "debug", skip(self, param_env, body_id, span))]
     fn implied_outlives_bounds(
         &self,
         param_env: ty::ParamEnv<'tcx>,
@@ -48,11 +48,10 @@
         ty: Ty<'tcx>,
         span: Span,
     ) -> Vec<OutlivesBound<'tcx>> {
-        debug!("implied_outlives_bounds(ty = {:?})", ty);
-
-        let mut orig_values = OriginalQueryValues::default();
-        let key = self.canonicalize_query(param_env.and(ty), &mut orig_values);
-        let result = match self.tcx.implied_outlives_bounds(key) {
+        let result = param_env
+            .and(type_op::implied_outlives_bounds::ImpliedOutlivesBounds { ty })
+            .fully_perform(self);
+        let result = match result {
             Ok(r) => r,
             Err(NoSolution) => {
                 self.tcx.sess.delay_span_bug(
@@ -62,32 +61,34 @@
                 return vec![];
             }
         };
-        assert!(result.value.is_proven());
 
-        let result = self.instantiate_query_response_and_region_obligations(
-            &ObligationCause::misc(span, body_id),
-            param_env,
-            &orig_values,
-            result,
-        );
-        debug!("implied_outlives_bounds for {:?}: {:#?}", ty, result);
-        let Ok(result) = result else {
-            self.tcx.sess.delay_span_bug(span, "implied_outlives_bounds failed to instantiate");
-            return vec![];
+        let TypeOpOutput { output, constraints, .. } = result;
+
+        if let Some(constraints) = constraints {
+            // Instantiation may have produced new inference variables and constraints on those
+            // variables. Process these constraints.
+            let mut fulfill_cx = FulfillmentContext::new();
+            let cause = ObligationCause::misc(span, body_id);
+            for &constraint in &constraints.outlives {
+                let obligation = self.query_outlives_constraint_to_obligation(
+                    constraint,
+                    cause.clone(),
+                    param_env,
+                );
+                fulfill_cx.register_predicate_obligation(self, obligation);
+            }
+            if !constraints.member_constraints.is_empty() {
+                span_bug!(span, "{:#?}", constraints.member_constraints);
+            }
+            let errors = fulfill_cx.select_all_or_error(self);
+            if !errors.is_empty() {
+                self.tcx.sess.delay_span_bug(
+                    span,
+                    "implied_outlives_bounds failed to solve obligations from instantiation",
+                );
+            }
         };
 
-        // Instantiation may have produced new inference variables and constraints on those
-        // variables. Process these constraints.
-        let mut fulfill_cx = FulfillmentContext::new();
-        fulfill_cx.register_predicate_obligations(self, result.obligations);
-        let errors = fulfill_cx.select_all_or_error(self);
-        if !errors.is_empty() {
-            self.tcx.sess.delay_span_bug(
-                span,
-                "implied_outlives_bounds failed to solve obligations from instantiation",
-            );
-        }
-
-        result.value
+        output
     }
 }
diff --git a/compiler/rustc_typeck/src/outlives/utils.rs b/compiler/rustc_typeck/src/outlives/utils.rs
index 54a5037..14e3048 100644
--- a/compiler/rustc_typeck/src/outlives/utils.rs
+++ b/compiler/rustc_typeck/src/outlives/utils.rs
@@ -21,7 +21,7 @@
 ) {
     // If the `'a` region is bound within the field type itself, we
     // don't want to propagate this constraint to the header.
-    if !is_free_region(tcx, outlived_region) {
+    if !is_free_region(outlived_region) {
         return;
     }
 
@@ -119,7 +119,7 @@
         }
 
         GenericArgKind::Lifetime(r) => {
-            if !is_free_region(tcx, r) {
+            if !is_free_region(r) {
                 return;
             }
             required_predicates.entry(ty::OutlivesPredicate(kind, outlived_region)).or_insert(span);
@@ -131,7 +131,7 @@
     }
 }
 
-fn is_free_region(tcx: TyCtxt<'_>, region: Region<'_>) -> bool {
+fn is_free_region(region: Region<'_>) -> bool {
     // First, screen for regions that might appear in a type header.
     match *region {
         // These correspond to `T: 'a` relationships:
@@ -144,13 +144,12 @@
         ty::ReEarlyBound(_) => true,
 
         // These correspond to `T: 'static` relationships which can be
-        // rather surprising. We are therefore putting this behind a
-        // feature flag:
+        // rather surprising.
         //
         //     struct Foo<'a, T> {
         //         field: &'static T, // this would generate a ReStatic
         //     }
-        ty::ReStatic => tcx.sess.features_untracked().infer_static_outlives_requirements,
+        ty::ReStatic => false,
 
         // Late-bound regions can appear in `fn` types:
         //
diff --git a/compiler/rustc_typeck/src/structured_errors/missing_cast_for_variadic_arg.rs b/compiler/rustc_typeck/src/structured_errors/missing_cast_for_variadic_arg.rs
index e2bd018..bafc5a0 100644
--- a/compiler/rustc_typeck/src/structured_errors/missing_cast_for_variadic_arg.rs
+++ b/compiler/rustc_typeck/src/structured_errors/missing_cast_for_variadic_arg.rs
@@ -4,14 +4,14 @@
 use rustc_session::Session;
 use rustc_span::Span;
 
-pub struct MissingCastForVariadicArg<'tcx> {
+pub struct MissingCastForVariadicArg<'tcx, 's> {
     pub sess: &'tcx Session,
     pub span: Span,
     pub ty: Ty<'tcx>,
-    pub cast_ty: &'tcx str,
+    pub cast_ty: &'s str,
 }
 
-impl<'tcx> StructuredDiagnostic<'tcx> for MissingCastForVariadicArg<'tcx> {
+impl<'tcx> StructuredDiagnostic<'tcx> for MissingCastForVariadicArg<'tcx, '_> {
     fn session(&self) -> &Session {
         self.sess
     }
diff --git a/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs b/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs
index 5cd7a7d..3224864 100644
--- a/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs
+++ b/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs
@@ -5,7 +5,6 @@
 };
 use rustc_hir as hir;
 use rustc_middle::hir::map::fn_sig;
-use rustc_middle::middle::resolve_lifetime::LifetimeScopeForPath;
 use rustc_middle::ty::{self as ty, AssocItems, AssocKind, TyCtxt};
 use rustc_session::Session;
 use rustc_span::def_id::DefId;
@@ -15,28 +14,28 @@
 
 /// Handles the `wrong number of type / lifetime / ... arguments` family of error messages.
 pub struct WrongNumberOfGenericArgs<'a, 'tcx> {
-    crate tcx: TyCtxt<'tcx>,
+    pub(crate) tcx: TyCtxt<'tcx>,
 
-    crate angle_brackets: AngleBrackets,
+    pub(crate) angle_brackets: AngleBrackets,
 
-    crate gen_args_info: GenericArgsInfo,
+    pub(crate) gen_args_info: GenericArgsInfo,
 
     /// Offending path segment
-    crate path_segment: &'a hir::PathSegment<'a>,
+    pub(crate) path_segment: &'a hir::PathSegment<'a>,
 
     /// Generic parameters as expected by type or trait
-    crate gen_params: &'a ty::Generics,
+    pub(crate) gen_params: &'a ty::Generics,
 
     /// Index offset into parameters. Depends on whether `Self` is included and on
     /// number of lifetime parameters in case we're processing missing or redundant
     /// type or constant arguments.
-    crate params_offset: usize,
+    pub(crate) params_offset: usize,
 
     /// Generic arguments as provided by user
-    crate gen_args: &'a hir::GenericArgs<'a>,
+    pub(crate) gen_args: &'a hir::GenericArgs<'a>,
 
     /// DefId of the generic type
-    crate def_id: DefId,
+    pub(crate) def_id: DefId,
 }
 
 // Provides information about the kind of arguments that were provided for
@@ -291,7 +290,69 @@
     }
 
     // Creates lifetime name suggestions from the lifetime parameter names
-    fn get_lifetime_args_suggestions_from_param_names(&self, num_params_to_take: usize) -> String {
+    fn get_lifetime_args_suggestions_from_param_names(
+        &self,
+        path_hir_id: Option<hir::HirId>,
+        num_params_to_take: usize,
+    ) -> String {
+        debug!(?path_hir_id);
+
+        if let Some(path_hir_id) = path_hir_id {
+            let mut ret = Vec::new();
+            for (id, node) in self.tcx.hir().parent_iter(path_hir_id) {
+                debug!(?id);
+                let params = if let Some(generics) = node.generics() {
+                    generics.params
+                } else if let hir::Node::Ty(ty) = node
+                    && let hir::TyKind::BareFn(bare_fn) = ty.kind
+                {
+                    bare_fn.generic_params
+                } else {
+                    &[]
+                };
+                ret.extend(params.iter().filter_map(|p| {
+                    let hir::GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Explicit }
+                        = p.kind
+                    else { return None };
+                    let hir::ParamName::Plain(name) = p.name else { return None };
+                    Some(name.to_string())
+                }));
+                // Suggest `'static` when in const/static item-like.
+                if let hir::Node::Item(hir::Item {
+                    kind: hir::ItemKind::Static { .. } | hir::ItemKind::Const { .. },
+                    ..
+                })
+                | hir::Node::TraitItem(hir::TraitItem {
+                    kind: hir::TraitItemKind::Const { .. },
+                    ..
+                })
+                | hir::Node::ImplItem(hir::ImplItem {
+                    kind: hir::ImplItemKind::Const { .. },
+                    ..
+                })
+                | hir::Node::ForeignItem(hir::ForeignItem {
+                    kind: hir::ForeignItemKind::Static { .. },
+                    ..
+                })
+                | hir::Node::AnonConst(..) = node
+                {
+                    ret.extend(
+                        std::iter::repeat("'static".to_owned())
+                            .take(num_params_to_take.saturating_sub(ret.len())),
+                    );
+                }
+                if ret.len() >= num_params_to_take {
+                    return ret[..num_params_to_take].join(", ");
+                }
+                // We cannot refer to lifetimes defined in an outer function.
+                if let hir::Node::Item(_) = node {
+                    break;
+                }
+            }
+        }
+
+        // We could not gather enough lifetime parameters in the scope.
+        // We use the parameter names from the target type's definition instead.
         self.gen_params
             .params
             .iter()
@@ -501,42 +562,10 @@
         let num_params_to_take = num_missing_args;
         let msg = format!("add missing {} argument{}", self.kind(), pluralize!(num_missing_args));
 
-        // we first try to get lifetime name suggestions from scope or elision information. If none is
-        // available we use the parameter definitions
-        let suggested_args = if let Some(hir_id) = self.path_segment.hir_id {
-            if let Some(lifetimes_in_scope) = self.tcx.lifetime_scope(hir_id) {
-                match lifetimes_in_scope {
-                    LifetimeScopeForPath::NonElided(param_names) => {
-                        debug!("NonElided(param_names: {:?})", param_names);
-
-                        if param_names.len() >= num_params_to_take {
-                            // use lifetime parameters in scope for suggestions
-                            param_names
-                                .iter()
-                                .take(num_params_to_take)
-                                .map(|p| p.as_str())
-                                .collect::<Vec<_>>()
-                                .join(", ")
-                        } else {
-                            // Not enough lifetime arguments in scope -> create suggestions from
-                            // lifetime parameter names in definition. An error for the incorrect
-                            // lifetime scope will be output later.
-                            self.get_lifetime_args_suggestions_from_param_names(num_params_to_take)
-                        }
-                    }
-                    LifetimeScopeForPath::Elided => {
-                        debug!("Elided");
-                        // use suggestions of the form `<'_, '_>` in case lifetime can be elided
-                        ["'_"].repeat(num_params_to_take).join(",")
-                    }
-                }
-            } else {
-                self.get_lifetime_args_suggestions_from_param_names(num_params_to_take)
-            }
-        } else {
-            self.get_lifetime_args_suggestions_from_param_names(num_params_to_take)
-        };
-
+        let suggested_args = self.get_lifetime_args_suggestions_from_param_names(
+            self.path_segment.hir_id,
+            num_params_to_take,
+        );
         debug!("suggested_args: {:?}", &suggested_args);
 
         match self.angle_brackets {
@@ -686,7 +715,7 @@
             err.span_suggestion(
                 span_redundant_lt_args,
                 &msg_lifetimes,
-                String::new(),
+                "",
                 Applicability::MaybeIncorrect,
             );
         };
@@ -728,7 +757,7 @@
             err.span_suggestion(
                 span_redundant_type_or_const_args,
                 &msg_types_or_consts,
-                String::new(),
+                "",
                 Applicability::MaybeIncorrect,
             );
         };
@@ -768,7 +797,7 @@
                 if self.gen_args.parenthesized { "parenthetical " } else { "" },
             );
 
-            err.span_suggestion(span, &msg, String::new(), Applicability::MaybeIncorrect);
+            err.span_suggestion(span, &msg, "", Applicability::MaybeIncorrect);
         } else if redundant_lifetime_args && redundant_type_or_const_args {
             remove_lifetime_args(err);
             remove_type_or_const_args(err);
diff --git a/compiler/rustc_typeck/src/variance/constraints.rs b/compiler/rustc_typeck/src/variance/constraints.rs
index 690c362..a7dcbff 100644
--- a/compiler/rustc_typeck/src/variance/constraints.rs
+++ b/compiler/rustc_typeck/src/variance/constraints.rs
@@ -411,12 +411,12 @@
     fn add_constraints_from_const(
         &mut self,
         current: &CurrentItem,
-        val: ty::Const<'tcx>,
+        c: ty::Const<'tcx>,
         variance: VarianceTermPtr<'a>,
     ) {
-        debug!("add_constraints_from_const(val={:?}, variance={:?})", val, variance);
+        debug!("add_constraints_from_const(c={:?}, variance={:?})", c, variance);
 
-        match &val.val() {
+        match &c.kind() {
             ty::ConstKind::Unevaluated(uv) => {
                 self.add_constraints_from_invariant_substs(current, uv.substs, variance);
             }